summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 16:35:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 15:45:54 +0000
commit32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch)
treeeeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/third_party/blink/renderer/modules
parent99677208ff3b216fdfec551fbe548da5520cd6fb (diff)
downloadqtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/modules')
-rw-r--r--chromium/third_party/blink/renderer/modules/BUILD.gn36
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc204
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc278
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc74
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc390
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object_test.cc170
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc437
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object.h140
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc402
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h51
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc98
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc203
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc96
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc123
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc85
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc8
-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/data/selection/aria-hidden-ax.txt23
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng-disabled.txt78
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng.txt90
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt15
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/svg-ax.txt27
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/table-ax.txt172
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc54
-rw-r--r--chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/background_sync/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/background_sync/sync_manager.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_service.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/bluetooth/request_device_options.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.cc637
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache.h29
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_storage.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/BUILD.gn6
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc57
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc2
-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/identifiability_study_helper.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc21
-rw-r--r--chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc99
-rw-r--r--chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/content_index/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn7
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/README.md20
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.cc40
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_inputs.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_outputs.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h20
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc50
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credential_properties_output.idl8
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc77
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/credentialmanager/idls.gni1
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc41
-rw-r--r--chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc626
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn12
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS5
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/README.md6
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/idls.gni7
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc267
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h91
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl19
-rw-r--r--chromium/third_party/blink/renderer/modules/direct_sockets/socket_options.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/encoding/README.md11
-rw-r--r--chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_ax_context.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc203
-rw-r--r--chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn (renamed from chromium/third_party/blink/renderer/modules/native_file_system/BUILD.gn)2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/DEPS (renamed from chromium/third_party/blink/renderer/modules/native_file_system/DEPS)2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/OWNERS (renamed from chromium/third_party/blink/renderer/modules/native_file_system/OWNERS)2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/README.md (renamed from chromium/third_party/blink/renderer/modules/native_file_system/README.md)16
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.cc)20
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.h)8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/directory_picker_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_picker_accept_type.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_picker_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_directory_handle.idl)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_directory_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_file_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle.idl)2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle_permission_descriptor.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_remove_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/file_system_writable_file_stream.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.cc)64
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.h)13
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system_test.cc)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/idls.gni (renamed from chromium/third_party/blink/renderer/modules/native_file_system/idls.gni)3
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc)67
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h)15
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.cc)8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.h)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.idl)2
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.cc)4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.h)8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc)12
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h)12
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.cc)6
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.h)8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc)4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h)10
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/open_file_picker_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/save_file_picker_options.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc (renamed from chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.cc)8
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h (renamed from chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.h)6
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/window_native_file_system.idl)4
-rw-r--r--chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl (renamed from chromium/third_party/blink/renderer/modules/native_file_system/write_params.idl)0
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/directory_entry.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/directory_entry_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/directory_reader.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/entry.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/entry_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_entry.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_entry_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_writer.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/filesystem/metadata.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc45
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_manager.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_manager.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/font_access/font_metadata.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_haptic_actuator.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc80
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_collection_info.cc69
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_collection_info.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl17
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device.cc185
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_device_test.cc (renamed from chromium/third_party/blink/renderer/modules/hid/hid_report_item_test.cc)118
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_info.cc34
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_info.h37
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_info.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_item.cc123
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_item.h83
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl49
-rw-r--r--chromium/third_party/blink/renderer/modules/hid/idls.gni6
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_detector.cc38
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_detector.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_detector.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_manager.cc110
-rw-r--r--chromium/third_party/blink/renderer/modules/idle/idle_manager.h53
-rw-r--r--chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/imagecapture/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc22
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc56
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.h17
-rw-r--r--chromium/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl_unittest.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc46
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/launch_params.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/launch_params.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/locks/lock_manager.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/media/BUILD.gn24
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/DEPS29
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.cc250
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h181
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager_test.cc786
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.cc365
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h125
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache_test.cc422
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/fuchsia_audio_device_factory.cc72
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.cc123
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h99
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc_test.cc321
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.cc254
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h116
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc_test.cc636
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/web_audio_device_factory.cc235
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/web_audio_input_ipc_factory.cc109
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory.cc149
-rw-r--r--chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory_test.cc254
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc63
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc261
-rw-r--r--chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc190
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h74
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.cc (renamed from chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.cc)321
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.h (renamed from chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.h)134
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc13
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h59
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.cc26
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h38
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.h35
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc220
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h78
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.cc (renamed from chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.cc)11
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h43
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc93
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/track_default.cc15
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/track_default.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/url_media_source.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn12
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream.h12
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc62
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_content_test.cc58
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc80
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h13
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc150
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc11
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc16
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_idl_files.gni3
-rw-r--r--chromium/third_party/blink/renderer/modules/modules_initializer.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options.idl18
-rw-r--r--chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options_accepts.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/native_file_system/get_system_directory_options.idl13
-rw-r--r--chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc64
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_scan_options.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/ndef_write_options.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc45
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc29
-rw-r--r--chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/goods/item_details.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.cc54
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc203
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payments_validators.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/payments/payments_validators.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc18
-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.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc39
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc405
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h36
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc610
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h27
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc70
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc82
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h23
-rw-r--r--chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.cc88
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/plugins/plugin.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h11
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc177
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/modules/push_messaging/push_manager.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/idls.gni2
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h19
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl7
-rw-r--r--chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc47
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor_test.cc79
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn14
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc74
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_grammar.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_alternative.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_result.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_recognition_result_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc30
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/speech/speech_synthesis_voice.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/storage/storage_controller.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc109
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h39
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/README.md14
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc12
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_type.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn8
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc84
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h53
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc415
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.cc65
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc55
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/panner_node.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc66
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h47
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn9
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/OWNERS3
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h6
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/idls.gni5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc35
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc51
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc191
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h14
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc57
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl10
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_error.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_blend_min_max.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_float.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.idl6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_float_blend.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_frag_depth.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_srgb.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_rgtc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ext_texture_norm_16.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_draw_buffers_indexed.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_element_index_uint.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_fbo_render_mipmap.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_standard_derivatives.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_texture_float.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_texture_float_linear.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc19
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_color_buffer_float.idl5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_debug_shaders.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_depth_texture.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_draw_buffers.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_lose_context.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc281
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h14
-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_timer_query_ext.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc43
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu.cc53
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc10
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl4
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc22
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc17
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl9
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc38
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc59
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h33
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl11
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set_descriptor.idl25
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc83
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl30
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc25
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h7
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl1
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc32
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl2
-rw-r--r--chromium/third_party/blink/renderer/modules/webgpu/idls.gni2
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc34
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc14
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc28
-rw-r--r--chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h23
-rw-r--r--chromium/third_party/blink/renderer/modules/webrtc/BUILD.gn3
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/FILE_TYPES.md51
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc33
-rw-r--r--chromium/third_party/blink/renderer/modules/webshare/navigator_share.h3
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc67
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h9
-rw-r--r--chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/BUILD.gn5
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/idls.gni1
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc3
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc24
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h10
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/quic_transport.idl14
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/web_transport.cc27
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/web_transport.h83
-rw-r--r--chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl26
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/idls.gni1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc8
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/navigator_xr.h4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_anchor.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc4
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc93
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h50
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl20
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.cc23
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.h5
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame.idl3
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc18
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.h16
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_input_source.h2
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_plane.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.cc95
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_session.h31
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_system.cc70
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_system.h1
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.cc9
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_view.h8
-rw-r--r--chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc6
645 files changed, 16923 insertions, 5435 deletions
diff --git a/chromium/third_party/blink/renderer/modules/BUILD.gn b/chromium/third_party/blink/renderer/modules/BUILD.gn
index 66d3b97751e..694ff382d40 100644
--- a/chromium/third_party/blink/renderer/modules/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/BUILD.gn
@@ -98,6 +98,7 @@ component("modules") {
"//third_party/blink/renderer/modules/eventsource",
"//third_party/blink/renderer/modules/exported",
"//third_party/blink/renderer/modules/filesystem",
+ "//third_party/blink/renderer/modules/file_system_access",
"//third_party/blink/renderer/modules/font_access",
"//third_party/blink/renderer/modules/gamepad",
"//third_party/blink/renderer/modules/geolocation",
@@ -121,7 +122,6 @@ component("modules") {
"//third_party/blink/renderer/modules/mediastream",
"//third_party/blink/renderer/modules/media",
"//third_party/blink/renderer/modules/webrtc",
- "//third_party/blink/renderer/modules/native_file_system",
"//third_party/blink/renderer/modules/native_io",
"//third_party/blink/renderer/modules/navigatorcontentutils",
"//third_party/blink/renderer/modules/netinfo",
@@ -136,6 +136,7 @@ component("modules") {
"//third_party/blink/renderer/modules/presentation",
"//third_party/blink/renderer/modules/push_messaging",
"//third_party/blink/renderer/modules/quota",
+ "//third_party/blink/renderer/modules/direct_sockets",
"//third_party/blink/renderer/modules/remoteplayback",
"//third_party/blink/renderer/modules/sanitizer_api",
"//third_party/blink/renderer/modules/scheduler",
@@ -167,6 +168,8 @@ component("modules") {
if (is_android) {
sub_modules += [ "//third_party/blink/renderer/modules/remote_objects" ]
+ } else {
+ sub_modules += [ "//third_party/blink/renderer/modules/serial" ]
}
deps = [
@@ -187,10 +190,6 @@ component("modules") {
public_deps = sub_modules
allow_circular_includes_from = sub_modules
- if (!is_android) {
- deps += [ "//third_party/blink/renderer/modules/serial" ]
- }
-
if (is_win) {
cflags =
[ "/wd4334" ] # Result of 32-bit shift implicitly converted to 64 bits.
@@ -246,9 +245,11 @@ source_set("modules_testing") {
"//third_party/blink/renderer/core:blink_core_pch",
]
+ public_deps = [ "//testing/gmock:gmock" ]
deps = [
"//third_party/blink/renderer/bindings/modules/v8:testing",
"//third_party/blink/renderer/core",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules",
]
}
@@ -269,6 +270,7 @@ source_set("unit_tests") {
"accessibility/accessibility_object_model_test.cc",
"accessibility/ax_inline_text_box_test.cc",
"accessibility/ax_layout_object_test.cc",
+ "accessibility/ax_node_object_test.cc",
"accessibility/ax_object_cache_test.cc",
"accessibility/ax_object_test.cc",
"accessibility/ax_position_test.cc",
@@ -323,6 +325,11 @@ source_set("unit_tests") {
"manifest/manifest_manager_unittest.cc",
"manifest/manifest_parser_unittest.cc",
"manifest/manifest_type_converters_unittest.cc",
+ "media/audio/audio_renderer_mixer_manager_test.cc",
+ "media/audio/audio_renderer_sink_cache_test.cc",
+ "media/audio/mojo_audio_input_ipc_test.cc",
+ "media/audio/mojo_audio_output_ipc_test.cc",
+ "media/audio/web_audio_output_ipc_factory_test.cc",
"media/webmediaplayer_util_unittest.cc",
"media_capabilities/media_capabilities_test.cc",
"media_controls/elements/media_control_animated_arrow_container_element_test.cc",
@@ -379,6 +386,7 @@ source_set("unit_tests") {
"payments/payment_address_test.cc",
"payments/payment_event_data_conversion_test.cc",
"payments/payment_request_details_test.cc",
+ "payments/payment_request_for_invalid_origin_or_ssl_test.cc",
"payments/payment_request_optional_total_test.cc",
"payments/payment_request_test.cc",
"payments/payment_request_update_event_test.cc",
@@ -423,6 +431,7 @@ source_set("unit_tests") {
"presentation/mock_presentation_service.h",
"presentation/presentation_availability_state_test.cc",
"presentation/presentation_availability_test.cc",
+ "presentation/presentation_connection_callbacks_test.cc",
"presentation/presentation_receiver_test.cc",
"presentation/presentation_request_test.cc",
"push_messaging/push_manager_test.cc",
@@ -491,23 +500,34 @@ source_set("unit_tests") {
"//components/schema_org/common:mojom_blink",
"//media:test_support",
"//media/mojo/mojom",
+ "//media/webrtc:webrtc",
"//mojo/public/cpp/bindings",
"//net:quic_test_tools",
+ "//net:test_support",
"//services/device/public/cpp:test_support",
"//skia",
"//testing/gmock",
"//testing/gtest",
"//third_party/blink/public:blink_headers",
+ "//third_party/blink/public:test_headers",
+ "//third_party/blink/public/strings:strings_grit",
+ "//third_party/blink/renderer/controller:blink_bindings_test_sources",
"//third_party/blink/renderer/core",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/core:unit_test_support",
+ "//third_party/blink/renderer/modules/file_system_access:unit_tests",
"//third_party/blink/renderer/modules/gamepad:unit_tests",
"//third_party/blink/renderer/modules/hid:unit_tests",
- "//third_party/blink/renderer/modules/native_file_system:unit_tests",
+ "//third_party/blink/renderer/modules/mediarecorder:buildflags",
+ "//third_party/blink/renderer/modules/mediastream:test_support",
+ "//third_party/blink/renderer/modules/peerconnection:test_support",
"//third_party/blink/renderer/modules/storage:unit_tests",
"//third_party/blink/renderer/modules/webcodecs:unit_tests",
"//third_party/blink/renderer/modules/webtransport:unit_tests",
"//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform:test_support",
"//third_party/blink/renderer/platform/wtf",
+ "//third_party/googletest:gmock",
"//third_party/opus",
"//third_party/webrtc_overrides:webrtc_component",
"//v8",
@@ -547,6 +567,7 @@ if (use_libfuzzer) {
deps = [
":modules",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules/media_capabilities:fuzzer_media_configuration_proto",
"//third_party/blink/renderer/platform:blink_fuzzer_test_support",
"//third_party/libprotobuf-mutator",
@@ -565,6 +586,7 @@ if (use_libfuzzer) {
deps = [
":modules",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules/webcodecs:fuzzer_protos",
"//third_party/blink/renderer/platform:blink_fuzzer_test_support",
"//third_party/libprotobuf-mutator",
@@ -583,6 +605,7 @@ if (use_libfuzzer) {
deps = [
":modules",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules/webcodecs:fuzzer_protos",
"//third_party/blink/renderer/platform:blink_fuzzer_test_support",
"//third_party/libprotobuf-mutator",
@@ -601,6 +624,7 @@ if (use_libfuzzer) {
deps = [
":modules",
+ "//third_party/blink/renderer/core:testing",
"//third_party/blink/renderer/modules/webcodecs:fuzzer_protos",
"//third_party/blink/renderer/platform:blink_fuzzer_test_support",
"//third_party/libprotobuf-mutator",
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
index d2f05f0405a..c4724fbce3a 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn
@@ -65,6 +65,9 @@ blink_modules_sources("accessibility") {
]
deps = [
+ "//third_party/blink/public/strings:strings_grit",
+ "//third_party/blink/renderer/modules/media_controls:media_controls",
+ "//third_party/blink/renderer/modules/permissions:permissions",
"//ui/accessibility:ax_base",
"//ui/accessibility:ax_enums_mojo_blink",
]
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/DEPS b/chromium/third_party/blink/renderer/modules/accessibility/DEPS
index 01bddf12d70..2bfd7d06e2e 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/DEPS
+++ b/chromium/third_party/blink/renderer/modules/accessibility/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"-third_party/blink/renderer/modules",
+ "+base/strings/string_util.h",
"+third_party/blink/renderer/modules/accessibility",
"+third_party/blink/renderer/modules/media_controls",
"+third_party/blink/renderer/modules/modules_export.h",
@@ -7,6 +8,7 @@ include_rules = [
"+ui/accessibility/ax_enums.mojom-blink.h",
"+ui/accessibility/ax_enums.mojom-blink-forward.h",
"+ui/accessibility/ax_event.h",
+ "+ui/accessibility/ax_mode.h",
"+ui/accessibility/ax_node_data.h",
"+ui/accessibility/ax_role_properties.h",
]
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 b1e28d4ea1c..8286fb5266e 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
@@ -285,16 +285,6 @@ class SparseAttributeAdapter : public AXSparseAttributeClient {
bool_attributes.insert(attribute, value);
}
- void AddIntAttribute(AXIntAttribute attribute, int32_t value) override {
- ASSERT_TRUE(int_attributes.find(attribute) == int_attributes.end());
- int_attributes.insert(attribute, value);
- }
-
- void AddUIntAttribute(AXUIntAttribute attribute, uint32_t value) override {
- ASSERT_TRUE(uint_attributes.find(attribute) == uint_attributes.end());
- uint_attributes.insert(attribute, value);
- }
-
void AddStringAttribute(AXStringAttribute attribute,
const String& value) override {
ASSERT_TRUE(string_attributes.find(attribute) == string_attributes.end());
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 30a64429c19..cf8028c450c 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
@@ -28,13 +28,21 @@
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
-#include "third_party/blink/renderer/core/dom/range.h"
+#include <utility>
+
+#include "base/numerics/clamped_math.h"
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
+#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/layout_text.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/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h"
#include "third_party/blink/renderer/modules/accessibility/ax_range.h"
-#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
@@ -43,22 +51,8 @@ AXInlineTextBox::AXInlineTextBox(
AXObjectCacheImpl& ax_object_cache)
: AXObject(ax_object_cache), inline_text_box_(std::move(inline_text_box)) {}
-void AXInlineTextBox::Init() {}
-
-void AXInlineTextBox::Detach() {
- AXObject::Detach();
- inline_text_box_ = nullptr;
-}
-
-bool AXInlineTextBox::IsLineBreakingObject() const {
- if (IsDetached())
- return AXObject::IsLineBreakingObject();
-
- // If this object is a forced line break, or the parent is a <br>
- // element, then this object is line breaking.
- const AXObject* parent = ParentObject();
- return inline_text_box_->IsLineBreak() ||
- (parent && parent->RoleValue() == ax::mojom::Role::kLineBreak);
+ax::mojom::blink::Role AXInlineTextBox::RoleValue() const {
+ return ax::mojom::blink::Role::kInlineTextBox;
}
void AXInlineTextBox::GetRelativeBounds(AXObject** out_container,
@@ -70,8 +64,9 @@ void AXInlineTextBox::GetRelativeBounds(AXObject** out_container,
out_container_transform.setIdentity();
if (!inline_text_box_ || !ParentObject() ||
- !ParentObject()->GetLayoutObject())
+ !ParentObject()->GetLayoutObject()) {
return;
+ }
*out_container = ParentObject();
out_bounds_in_container = FloatRect(inline_text_box_->LocalBounds());
@@ -99,17 +94,16 @@ bool AXInlineTextBox::ComputeAccessibilityIsIgnored(
}
void AXInlineTextBox::TextCharacterOffsets(Vector<int>& offsets) const {
- if (!inline_text_box_)
+ if (IsDetached())
return;
- unsigned len = inline_text_box_->Len();
Vector<float> widths;
inline_text_box_->CharacterWidths(widths);
- DCHECK_EQ(widths.size(), len);
- offsets.resize(len);
+ DCHECK_EQ(int{widths.size()}, TextLength());
+ offsets.resize(TextLength());
float width_so_far = 0;
- for (unsigned i = 0; i < len; i++) {
+ for (int i = 0; i < TextLength(); i++) {
width_so_far += widths[i];
offsets[i] = roundf(width_so_far);
}
@@ -118,8 +112,9 @@ void AXInlineTextBox::TextCharacterOffsets(Vector<int>& offsets) const {
void AXInlineTextBox::GetWordBoundaries(Vector<int>& word_starts,
Vector<int>& word_ends) const {
if (!inline_text_box_ ||
- inline_text_box_->GetText().ContainsOnlyWhitespaceOrEmpty())
+ inline_text_box_->GetText().ContainsOnlyWhitespaceOrEmpty()) {
return;
+ }
Vector<AbstractInlineTextBox::WordBoundaries> boundaries;
inline_text_box_->GetWordBoundaries(boundaries);
@@ -131,19 +126,44 @@ void AXInlineTextBox::GetWordBoundaries(Vector<int>& word_starts,
}
}
-unsigned AXInlineTextBox::TextOffsetInContainer(unsigned offset) const {
- if (!inline_text_box_)
+int AXInlineTextBox::TextOffsetInFormattingContext(int offset) const {
+ DCHECK_GE(offset, 0);
+ if (IsDetached())
+ return 0;
+
+ // Retrieve the text offset from the start of the layout block flow ancestor.
+ return int{inline_text_box_->TextOffsetInFormattingContext(
+ static_cast<unsigned int>(offset))};
+}
+
+int AXInlineTextBox::TextOffsetInContainer(int offset) const {
+ DCHECK_GE(offset, 0);
+ if (IsDetached())
return 0;
- return inline_text_box_->TextOffsetInContainer(offset);
+ // Retrieve the text offset from the start of the layout block flow ancestor.
+ int offset_in_block_flow_container = TextOffsetInFormattingContext(offset);
+ const AXObject* parent = ParentObject();
+ if (!parent)
+ return offset_in_block_flow_container;
+
+ // If the parent object in the accessibility tree exists, then it is either
+ // a static text object or a line break. In the static text case, it is an
+ // AXLayoutObject associated with an inline text object. Hence the container
+ // is another inline object, not a layout block flow. We need to subtract the
+ // text start offset of the static text parent from the text start offset of
+ // this inline text box.
+ int offset_in_inline_parent = parent->TextOffsetInFormattingContext(0);
+ DCHECK_LE(offset_in_inline_parent, offset_in_block_flow_container);
+ return offset_in_block_flow_container - offset_in_inline_parent;
}
-String AXInlineTextBox::GetName(ax::mojom::NameFrom& name_from,
+String AXInlineTextBox::GetName(ax::mojom::blink::NameFrom& name_from,
AXObject::AXObjectVector* name_objects) const {
- if (!inline_text_box_)
+ if (IsDetached())
return String();
- name_from = ax::mojom::NameFrom::kContents;
+ name_from = ax::mojom::blink::NameFrom::kContents;
return inline_text_box_->GetText();
}
@@ -161,7 +181,7 @@ AXObject* AXInlineTextBox::ComputeParent() const {
// In addition to LTR and RTL direction, edit fields also support
// top to bottom and bottom to top via the CSS writing-mode property.
ax::mojom::blink::WritingDirection AXInlineTextBox::GetTextDirection() const {
- if (!inline_text_box_)
+ if (IsDetached())
return AXObject::GetTextDirection();
switch (inline_text_box_->GetDirection()) {
@@ -179,13 +199,16 @@ ax::mojom::blink::WritingDirection AXInlineTextBox::GetTextDirection() const {
}
Node* AXInlineTextBox::GetNode() const {
- if (!inline_text_box_)
+ if (IsDetached())
return nullptr;
return inline_text_box_->GetNode();
}
AXObject* AXInlineTextBox::NextOnLine() const {
+ if (IsDetached())
+ return nullptr;
+
if (inline_text_box_->IsLast())
return ParentObject()->NextOnLine();
@@ -198,6 +221,9 @@ AXObject* AXInlineTextBox::NextOnLine() const {
}
AXObject* AXInlineTextBox::PreviousOnLine() const {
+ if (IsDetached())
+ return nullptr;
+
if (inline_text_box_->IsFirst())
return ParentObject()->PreviousOnLine();
@@ -209,4 +235,116 @@ AXObject* AXInlineTextBox::PreviousOnLine() const {
return nullptr;
}
+void AXInlineTextBox::GetDocumentMarkers(
+ Vector<DocumentMarker::MarkerType>* marker_types,
+ Vector<AXRange>* marker_ranges) const {
+ if (!RuntimeEnabledFeatures::
+ AccessibilityUseAXPositionForDocumentMarkersEnabled())
+ return;
+
+ if (IsDetached())
+ return;
+
+ int text_length = TextLength();
+ if (!text_length)
+ return;
+ const auto ax_range = AXRange::RangeOfContents(*this);
+
+ // First use ARIA markers for spelling/grammar if available.
+ base::Optional<DocumentMarker::MarkerType> aria_marker_type =
+ GetAriaSpellingOrGrammarMarker();
+ if (aria_marker_type) {
+ marker_types->push_back(aria_marker_type.value());
+ marker_ranges->push_back(ax_range);
+ }
+
+ DocumentMarkerController& marker_controller = GetDocument()->Markers();
+ const Position dom_range_start =
+ ax_range.Start().ToPosition(AXPositionAdjustmentBehavior::kMoveLeft);
+ const Position dom_range_end =
+ ax_range.End().ToPosition(AXPositionAdjustmentBehavior::kMoveRight);
+ if (dom_range_start.IsNull() || dom_range_end.IsNull())
+ return;
+
+ const EphemeralRangeInFlatTree dom_range(
+ ToPositionInFlatTree(dom_range_start),
+ ToPositionInFlatTree(dom_range_end));
+ DCHECK(dom_range.IsNotNull());
+ const DocumentMarker::MarkerTypes markers_used_by_accessibility(
+ DocumentMarker::kSpelling | DocumentMarker::kGrammar |
+ DocumentMarker::kTextMatch | DocumentMarker::kActiveSuggestion |
+ DocumentMarker::kSuggestion | DocumentMarker::kTextFragment);
+ // "MarkersIntersectingRange" performs a binary search through the document
+ // markers list for markers in the given range and of the given types. It
+ // should be of a logarithmic complexity.
+ const VectorOfPairs<const Text, DocumentMarker> node_marker_pairs =
+ marker_controller.MarkersIntersectingRange(dom_range,
+ markers_used_by_accessibility);
+ const int start_text_offset_in_parent = TextOffsetInContainer(0);
+ for (const auto& node_marker_pair : node_marker_pairs) {
+ DCHECK_EQ(GetNode(), node_marker_pair.first);
+ const DocumentMarker* marker = node_marker_pair.second;
+
+ if (aria_marker_type == marker->GetType())
+ continue;
+
+ // The document markers are represented by DOM offsets in this object's
+ // static text parent. We need to translate to text offsets in the
+ // accessibility tree, first in this object's parent and then to local text
+ // offsets.
+ const auto start_position = AXPosition::FromPosition(
+ Position(*GetNode(), marker->StartOffset()), TextAffinity::kDownstream,
+ AXPositionAdjustmentBehavior::kMoveLeft);
+ const auto end_position = AXPosition::FromPosition(
+ Position(*GetNode(), marker->EndOffset()), TextAffinity::kDownstream,
+ AXPositionAdjustmentBehavior::kMoveRight);
+ if (!start_position.IsValid() || !end_position.IsValid())
+ continue;
+
+ const int local_start_offset = base::ClampMax(
+ start_position.TextOffset() - start_text_offset_in_parent, 0);
+ DCHECK_LE(local_start_offset, text_length);
+ const int local_end_offset = base::ClampMin(
+ end_position.TextOffset() - start_text_offset_in_parent, text_length);
+ DCHECK_GE(local_end_offset, 0);
+
+ marker_types->push_back(marker->GetType());
+ marker_ranges->emplace_back(
+ AXPosition::CreatePositionInTextObject(*this, local_start_offset),
+ AXPosition::CreatePositionInTextObject(*this, local_end_offset));
+ }
+}
+
+void AXInlineTextBox::Init() {}
+
+void AXInlineTextBox::Detach() {
+ inline_text_box_ = nullptr;
+ AXObject::Detach();
+}
+
+bool AXInlineTextBox::IsDetached() const {
+ return !inline_text_box_ || AXObject::IsDetached();
+}
+
+bool AXInlineTextBox::IsAXInlineTextBox() const {
+ return true;
+}
+
+bool AXInlineTextBox::IsLineBreakingObject() const {
+ if (IsDetached())
+ return AXObject::IsLineBreakingObject();
+
+ // If this object is a forced line break, or the parent is a <br>
+ // element, then this object is line breaking.
+ const AXObject* parent = ParentObject();
+ return inline_text_box_->IsLineBreak() ||
+ (parent && parent->RoleValue() == ax::mojom::blink::Role::kLineBreak);
+}
+
+int AXInlineTextBox::TextLength() const {
+ if (IsDetached())
+ return 0;
+ return int{inline_text_box_->Len()};
+}
+
} // namespace blink
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 ba665de0b88..57548db4e29 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
@@ -30,6 +30,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_INLINE_TEXT_BOX_H_
#include "base/macros.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
#include "third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
@@ -38,28 +39,21 @@ namespace blink {
class Node;
class AXObjectCacheImpl;
+// Encapsulates an AbstractInlineTextBox and adapts it for use in Blink's
+// accessibility tree.
class AXInlineTextBox final : public AXObject {
public:
AXInlineTextBox(scoped_refptr<AbstractInlineTextBox>, AXObjectCacheImpl&);
- protected:
- void Init() override;
- void Detach() override;
- bool IsDetached() const override { return !inline_text_box_; }
- bool IsAXInlineTextBox() const override { return true; }
-
- bool IsLineBreakingObject() const override;
-
- public:
- ax::mojom::Role RoleValue() const override {
- return ax::mojom::Role::kInlineTextBox;
- }
- String GetName(ax::mojom::NameFrom&,
+ // AXObject overrides.
+ ax::mojom::blink::Role RoleValue() const override;
+ String GetName(ax::mojom::blink::NameFrom&,
AXObject::AXObjectVector* name_objects) const override;
void TextCharacterOffsets(Vector<int>&) const override;
void GetWordBoundaries(Vector<int>& word_starts,
Vector<int>& word_ends) const override;
- unsigned TextOffsetInContainer(unsigned offset) const override;
+ int TextOffsetInFormattingContext(int offset) const override;
+ int TextOffsetInContainer(int offset) const override;
void GetRelativeBounds(AXObject** out_container,
FloatRect& out_bounds_in_container,
SkMatrix44& out_container_transform,
@@ -69,12 +63,22 @@ class AXInlineTextBox final : public AXObject {
Node* GetNode() const override;
AXObject* NextOnLine() const override;
AXObject* PreviousOnLine() const override;
+ void GetDocumentMarkers(Vector<DocumentMarker::MarkerType>* marker_types,
+ Vector<AXRange>* marker_ranges) const override;
- private:
- scoped_refptr<AbstractInlineTextBox> inline_text_box_;
+ protected:
+ void Init() override;
+ void Detach() override;
+ bool IsDetached() const override;
+ bool IsAXInlineTextBox() const override;
+ bool IsLineBreakingObject() const override;
+ int TextLength() const override;
+ private:
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
+ scoped_refptr<AbstractInlineTextBox> inline_text_box_;
+
DISALLOW_COPY_AND_ASSIGN(AXInlineTextBox);
};
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc
index 0160daf039c..bb4c02b5cb0 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box_test.cc
@@ -5,7 +5,12 @@
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.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/position.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_range.h"
#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -38,5 +43,278 @@ TEST_P(ParameterizedAccessibilityTest, GetWordBoundaries) {
EXPECT_EQ(expected_word_ends, word_ends);
}
+TEST_P(ParameterizedAccessibilityTest, GetDocumentMarkers) {
+ // There should be four inline text boxes in the following paragraph.
+ SetBodyInnerHTML(R"HTML(
+ <style>* { font-size: 10px; }</style>
+ <p id="paragraph" style="width: 10ch;">
+ Misspelled text with a grammar error.
+ </p>)HTML");
+
+ const Node* text = GetElementById("paragraph")->firstChild();
+ ASSERT_NE(nullptr, text);
+ ASSERT_TRUE(text->IsTextNode());
+
+ // Mark the part of the paragraph that says "Misspelled text" with a spelling
+ // marker, and the part that says "a grammar error" with a grammar marker.
+ //
+ // Note that the inline text boxes and the markers do not occupy the same text
+ // range. The ranges simply overlap. Also note that the marker ranges include
+ // non-collapsed white space found in the DOM.
+ DocumentMarkerController& marker_controller = GetDocument().Markers();
+ const EphemeralRange misspelled_range(Position(text, 9), Position(text, 24));
+ marker_controller.AddSpellingMarker(misspelled_range);
+ const EphemeralRange grammar_range(Position(text, 30), Position(text, 45));
+ marker_controller.AddGrammarMarker(grammar_range);
+
+ AXObject* ax_paragraph = GetAXObjectByElementId("paragraph");
+ ASSERT_NE(nullptr, ax_paragraph);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue());
+ ax_paragraph->LoadInlineTextBoxes();
+
+ // kStaticText: "Misspelled text with a grammar error.".
+ const AXObject* ax_text = ax_paragraph->FirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_text);
+ ASSERT_EQ(ax::mojom::Role::kStaticText, ax_text->RoleValue());
+ ASSERT_EQ(4, ax_text->ChildCountIncludingIgnored());
+
+ // For each inline text box, angle brackets indicate where the marker starts
+ // and ends respectively.
+
+ // kInlineTextBox: "<Misspelled >".
+ AXObject* ax_inline_text_box = ax_text->ChildAtIncludingIgnored(0);
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ VectorOf<DocumentMarker::MarkerType> marker_types;
+ VectorOf<AXRange> marker_ranges;
+ ax_inline_text_box->GetDocumentMarkers(&marker_types, &marker_ranges);
+ EXPECT_EQ((VectorOf<DocumentMarker::MarkerType>{DocumentMarker::kSpelling}),
+ marker_types);
+ EXPECT_EQ(
+ (VectorOf<AXRange>{AXRange(
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 0),
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 11))}),
+ marker_ranges);
+
+ // kInlineTextBox: "<text> with <a >".
+ ax_inline_text_box = ax_text->ChildAtIncludingIgnored(1);
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ marker_types.clear();
+ marker_ranges.clear();
+ ax_inline_text_box->GetDocumentMarkers(&marker_types, &marker_ranges);
+ EXPECT_EQ((VectorOf<DocumentMarker::MarkerType>{DocumentMarker::kSpelling,
+ DocumentMarker::kGrammar}),
+ marker_types);
+ EXPECT_EQ(
+ (VectorOf<AXRange>{
+ AXRange(
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 0),
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 4)),
+ AXRange(
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 10),
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box,
+ 12))}),
+ marker_ranges);
+
+ // kInlineTextBox: "<grammar >".
+ ax_inline_text_box = ax_text->ChildAtIncludingIgnored(2);
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ marker_types.clear();
+ marker_ranges.clear();
+ ax_inline_text_box->GetDocumentMarkers(&marker_types, &marker_ranges);
+ EXPECT_EQ((VectorOf<DocumentMarker::MarkerType>{DocumentMarker::kGrammar}),
+ marker_types);
+ EXPECT_EQ(
+ (VectorOf<AXRange>{AXRange(
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 0),
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 8))}),
+ marker_ranges);
+
+ // kInlineTextBox: "<error>.".
+ ax_inline_text_box = ax_text->ChildAtIncludingIgnored(3);
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ marker_types.clear();
+ marker_ranges.clear();
+ ax_inline_text_box->GetDocumentMarkers(&marker_types, &marker_ranges);
+ EXPECT_EQ((VectorOf<DocumentMarker::MarkerType>{DocumentMarker::kGrammar}),
+ marker_types);
+ EXPECT_EQ(
+ (VectorOf<AXRange>{AXRange(
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 0),
+ AXPosition::CreatePositionInTextObject(*ax_inline_text_box, 5))}),
+ marker_ranges);
+}
+
+TEST_P(ParameterizedAccessibilityTest, TextOffsetInContainerWithASpan) {
+ // There should be three inline text boxes in the following paragraph. The
+ // span should reset the text start offset of all of them to 0.
+ SetBodyInnerHTML(R"HTML(
+ <style>* { font-size: 10px; }</style>
+ <p id="paragraph">
+ Hello <span>world </span>there.
+ </p>)HTML");
+
+ AXObject* ax_paragraph = GetAXObjectByElementId("paragraph");
+ ASSERT_NE(nullptr, ax_paragraph);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue());
+ ax_paragraph->LoadInlineTextBoxes();
+
+ const AXObject* ax_inline_text_box =
+ ax_paragraph->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(1, ax_inline_text_box->TextOffsetInContainer(1));
+
+ ax_inline_text_box = ax_inline_text_box->NextInPreOrderIncludingIgnored()
+ ->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(2, ax_inline_text_box->TextOffsetInContainer(2));
+
+ ax_inline_text_box = ax_inline_text_box->NextInPreOrderIncludingIgnored()
+ ->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(3, ax_inline_text_box->TextOffsetInContainer(3));
+
+ ASSERT_EQ(nullptr, ax_inline_text_box->NextInPreOrderIncludingIgnored());
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInContainerWithMultipleInlineTextBoxes) {
+ // There should be four inline text boxes in the following paragraph. The span
+ // should not affect the text start offset of the text outside the span.
+ SetBodyInnerHTML(R"HTML(
+ <style>* { font-size: 10px; }</style>
+ <p id="paragraph" style="width: 5ch;">
+ <span>Offset</span>Hello world there.
+ </p>)HTML");
+
+ AXObject* ax_paragraph = GetAXObjectByElementId("paragraph");
+ ASSERT_NE(nullptr, ax_paragraph);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue());
+ ax_paragraph->LoadInlineTextBoxes();
+
+ const AXObject* ax_inline_text_box =
+ ax_paragraph->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(1, ax_inline_text_box->TextOffsetInContainer(1));
+
+ ax_inline_text_box = ax_inline_text_box->NextInPreOrderIncludingIgnored()
+ ->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(1, ax_inline_text_box->TextOffsetInContainer(1));
+
+ ax_inline_text_box = ax_inline_text_box->NextSiblingIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(6, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(8, ax_inline_text_box->TextOffsetInContainer(2));
+
+ ax_inline_text_box = ax_inline_text_box->NextSiblingIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(12, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(15, ax_inline_text_box->TextOffsetInContainer(3));
+
+ ASSERT_EQ(nullptr, ax_inline_text_box->NextInPreOrderIncludingIgnored());
+}
+
+TEST_P(ParameterizedAccessibilityTest, TextOffsetInContainerWithLineBreak) {
+ // There should be three inline text boxes in the following paragraph. The
+ // line break should reset the text start offset to 0 of both the inline text
+ // box inside the line break, as well as the text start ofset of the second
+ // line.
+ SetBodyInnerHTML(R"HTML(
+ <style>* { font-size: 10px; }</style>
+ <p id="paragraph">
+ Line one.<br>
+ Line two.
+ </p>)HTML");
+
+ AXObject* ax_paragraph = GetAXObjectByElementId("paragraph");
+ ASSERT_NE(nullptr, ax_paragraph);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue());
+ ax_paragraph->LoadInlineTextBoxes();
+
+ const AXObject* ax_inline_text_box =
+ ax_paragraph->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(1, ax_inline_text_box->TextOffsetInContainer(1));
+
+ ax_inline_text_box = ax_inline_text_box->NextInPreOrderIncludingIgnored()
+ ->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+
+ ax_inline_text_box = ax_inline_text_box->NextInPreOrderIncludingIgnored()
+ ->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+ EXPECT_EQ(0, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(2, ax_inline_text_box->TextOffsetInContainer(2));
+
+ ASSERT_EQ(nullptr, ax_inline_text_box->NextInPreOrderIncludingIgnored());
+}
+
+TEST_P(ParameterizedAccessibilityTest, TextOffsetInContainerWithBreakWord) {
+ // There should be three inline text boxes in the following paragraph because
+ // of the narrow width and the long word, coupled with the CSS "break-word"
+ // property. Each inline text box should have a different offset in container.
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>* { font: 10px/10px Ahem; }</style>
+ <p id="paragraph" style="width: 5ch; word-wrap: break-word;">
+ VeryLongWord
+ </p>)HTML");
+
+ AXObject* ax_paragraph = GetAXObjectByElementId("paragraph");
+ ASSERT_NE(nullptr, ax_paragraph);
+ ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue());
+ ax_paragraph->LoadInlineTextBoxes();
+
+ const AXObject* ax_inline_text_box =
+ ax_paragraph->DeepestFirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+
+ int text_start_offset = 0;
+ int text_end_offset = ax_inline_text_box->TextLength();
+ EXPECT_EQ(text_start_offset, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(text_end_offset, ax_inline_text_box->TextOffsetInContainer(
+ ax_inline_text_box->TextLength()));
+
+ ax_inline_text_box = ax_inline_text_box->NextSiblingIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+
+ text_start_offset = text_end_offset;
+ text_end_offset = text_start_offset + ax_inline_text_box->TextLength();
+ EXPECT_EQ(text_start_offset, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(text_end_offset, ax_inline_text_box->TextOffsetInContainer(
+ ax_inline_text_box->TextLength()));
+
+ ax_inline_text_box = ax_inline_text_box->NextSiblingIncludingIgnored();
+ ASSERT_NE(nullptr, ax_inline_text_box);
+ ASSERT_EQ(ax::mojom::Role::kInlineTextBox, ax_inline_text_box->RoleValue());
+
+ text_start_offset = text_end_offset;
+ text_end_offset = text_start_offset + ax_inline_text_box->TextLength();
+ EXPECT_EQ(text_start_offset, ax_inline_text_box->TextOffsetInContainer(0));
+ EXPECT_EQ(text_end_offset, ax_inline_text_box->TextOffsetInContainer(
+ ax_inline_text_box->TextLength()));
+
+ ASSERT_EQ(nullptr, ax_inline_text_box->NextSiblingIncludingIgnored());
+}
+
} // namespace test
} // namespace blink
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 0f8f4074ff8..e4857d1cc3a 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
@@ -71,7 +71,6 @@
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_table_row.h"
#include "third_party/blink/renderer/core/layout/layout_table_section.h"
-#include "third_party/blink/renderer/core/layout/layout_text_control.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/core/layout/list_marker.h"
@@ -85,6 +84,7 @@
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
+#include "third_party/blink/renderer/core/svg/svg_g_element.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
#include "third_party/blink/renderer/modules/accessibility/ax_image_map_link.h"
#include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h"
@@ -119,10 +119,9 @@ LayoutBoxModelObject* AXLayoutObject::GetLayoutBoxModelObject() const {
}
bool IsProgrammaticallyScrollable(LayoutBox* box) {
- if (!box->HasOverflowClip()) {
- // If overflow is visible it is not scrollable.
+ if (!box->IsScrollContainer())
return false;
- }
+
// Return true if the content is larger than the available space.
return box->PixelSnappedScrollWidth() != box->PixelSnappedClientWidth() ||
box->PixelSnappedScrollHeight() != box->PixelSnappedClientHeight();
@@ -338,7 +337,7 @@ bool AXLayoutObject::IsEditable() const {
const auto* elem = DynamicTo<Element>(node);
if (!elem)
elem = FlatTreeTraversal::ParentElement(*node);
- if (GetLayoutObject()->IsTextControl())
+ if (GetLayoutObject()->IsTextControlIncludingNG())
return true;
// Contrary to Firefox, we mark editable all auto-generated content, such as
@@ -363,6 +362,7 @@ bool AXLayoutObject::IsEditable() const {
// Requires layoutObject to be present because it relies on style
// user-modify. Don't move this logic to AXNodeObject.
+// Returns true for a contenteditable or any descendant of it.
bool AXLayoutObject::IsRichlyEditable() const {
if (IsDetached())
return false;
@@ -591,18 +591,12 @@ bool AXLayoutObject::IsPlaceholder() const {
return false;
LayoutObject* parent_layout_object = parent_object->GetLayoutObject();
- auto* layout_text_control =
- DynamicTo<LayoutTextControl>(parent_layout_object);
- if (!layout_text_control)
- return false;
-
- DCHECK(layout_text_control);
-
- TextControlElement* text_control_element =
- layout_text_control->GetTextControlElement();
- if (!text_control_element)
+ if (!parent_layout_object ||
+ !parent_layout_object->IsTextControlIncludingNG())
return false;
+ const auto* text_control_element =
+ To<TextControlElement>(parent_layout_object->GetNode());
HTMLElement* placeholder_element = text_control_element->PlaceholderElement();
return GetElement() == static_cast<Element*>(placeholder_element);
@@ -723,7 +717,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
// used to compute the character extent for index 0. This is the same as
// what the caret's bounds would be if the editable area is focused.
if (ParentObject() && ParentObject()->GetLayoutObject() &&
- ParentObject()->GetLayoutObject()->IsTextControl()) {
+ ParentObject()->GetLayoutObject()->IsTextControlIncludingNG()) {
return false;
}
@@ -745,6 +739,14 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
return true;
}
+ // If setting enabled, do not ignore SVG grouping (<g>) elements.
+ if (IsA<SVGGElement>(GetNode())) {
+ Settings* settings = GetDocument()->GetSettings();
+ if (settings->GetAccessibilityIncludeSvgGElement()) {
+ return false;
+ }
+ }
+
// By default, objects should be ignored so that the AX hierarchy is not
// filled with unnecessary items.
if (ignored_reasons)
@@ -1768,14 +1770,6 @@ AXObject* AXLayoutObject::ComputeParent() const {
if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar)
return AXObjectCache().GetOrCreate(layout_object_->Parent());
- // menuButton and its corresponding menu are DOM siblings, but Accessibility
- // needs them to be parent/child.
- if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenu) {
- AXObject* parent = MenuButtonForMenu();
- if (parent)
- return parent;
- }
-
if (GetNode())
return AXNodeObject::ComputeParent();
@@ -1799,14 +1793,6 @@ AXObject* AXLayoutObject::ComputeParentIfExists() const {
if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenuBar)
return AXObjectCache().Get(layout_object_->Parent());
- // menuButton and its corresponding menu are DOM siblings, but Accessibility
- // needs them to be parent/child.
- if (AriaRoleAttribute() == ax::mojom::blink::Role::kMenu) {
- AXObject* parent = MenuButtonForMenuIfExists();
- if (parent)
- return parent;
- }
-
if (GetNode())
return AXNodeObject::ComputeParentIfExists();
@@ -1910,14 +1896,14 @@ bool AXLayoutObject::OnNativeSetValueAction(const String& string) {
LayoutBoxModelObject* layout_object = ToLayoutBoxModelObject(layout_object_);
auto* html_input_element = DynamicTo<HTMLInputElement>(*GetNode());
- if (html_input_element && layout_object->IsTextField()) {
+ if (html_input_element && layout_object->IsTextFieldIncludingNG()) {
html_input_element->setValue(
string, TextFieldEventBehavior::kDispatchInputAndChangeEvent);
return true;
}
if (auto* text_area_element = DynamicTo<HTMLTextAreaElement>(*GetNode())) {
- DCHECK(layout_object->IsTextArea());
+ DCHECK(layout_object->IsTextAreaIncludingNG());
text_area_element->setValue(
string, TextFieldEventBehavior::kDispatchInputAndChangeEvent);
return true;
@@ -1943,11 +1929,11 @@ bool AXLayoutObject::OnNativeSetValueAction(const String& string) {
//
void AXLayoutObject::HandleActiveDescendantChanged() {
- if (!GetLayoutObject())
+ if (!GetLayoutObject() || !GetNode() || !GetDocument())
return;
- AXObject* focused_object = AXObjectCache().FocusedObject();
- if (focused_object == this) {
+ Node* focused_node = GetDocument()->FocusedElement();
+ if (focused_node == GetNode()) {
AXObject* active_descendant = ActiveDescendant();
if (active_descendant && active_descendant->IsSelectedFromFocus()) {
// In single selection containers, selection follows focus, so a selection
@@ -2024,20 +2010,6 @@ void AXLayoutObject::HandleAutofillStateChanged(WebAXAutofillState state) {
AXObjectCache().SetAutofillState(AXObjectID(), state);
}
-void AXLayoutObject::TextChanged() {
- if (!layout_object_)
- return;
-
- Settings* settings = GetDocument()->GetSettings();
- if (settings && settings->GetInlineTextBoxAccessibilityEnabled() &&
- RoleValue() == ax::mojom::blink::Role::kStaticText)
- ChildrenChanged();
-
- // Do this last - AXNodeObject::textChanged posts live region announcements,
- // and we should update the inline text boxes first.
- AXNodeObject::TextChanged();
-}
-
// The following is a heuristic used to determine if a
// <table> should be with ax::mojom::blink::Role::kTable or
// ax::mojom::blink::Role::kLayoutTable.
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 97579857b7b..7517cae747d 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
@@ -152,7 +152,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
void HandleAriaExpandedChanged() override;
// Called when autofill/autocomplete state changes on a form control.
void HandleAutofillStateChanged(WebAXAutofillState state) override;
- void TextChanged() override;
// For a table.
bool IsDataTable() const override;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
index 8fff570a90b..82a5489b3e9 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
@@ -75,7 +75,11 @@ void AXMenuList::AddChildren() {
AXObjectCacheImpl& cache = AXObjectCache();
- AXObject* popup = cache.Create(ax::mojom::blink::Role::kMenuListPopup, this);
+ AXObject* popup = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup);
+ if (!popup)
+ return;
+
+ To<AXMockObject>(popup)->SetParent(this);
if (!popup->AccessibilityIsIncludedInTree()) {
cache.Remove(popup->AXObjectID());
return;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
index 097d5b77a9f..97e9204a54f 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc
@@ -152,8 +152,11 @@ bool AXMenuListOption::OnNativeSetSelectedAction(bool b) {
bool AXMenuListOption::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
- if (IsInertOrAriaHidden())
+ if (IsInertOrAriaHidden()) {
+ if (ignored_reasons)
+ ComputeIsInertOrAriaHidden(ignored_reasons);
return true;
+ }
if (DynamicTo<HTMLOptionElement>(GetNode())->FastHasAttribute(
html_names::kHiddenAttr))
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
index c8e5fe81f3c..b4cbcf00e70 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
@@ -53,7 +53,11 @@ AXRestriction AXMenuListPopup::Restriction() const {
bool AXMenuListPopup::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
- return AccessibilityIsIgnoredByDefault(ignored_reasons);
+ // Base whether the menupopup is ignored on the containing <select>.
+ if (parent_)
+ return parent_->ComputeAccessibilityIsIgnored(ignored_reasons);
+
+ return kIgnoreObject;
}
AXMenuListOption* AXMenuListPopup::MenuListOptionAXObject(
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 774da8a5030..39816e2341a 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
@@ -29,13 +29,16 @@
#include "third_party/blink/renderer/modules/accessibility/ax_node_object.h"
#include <math.h>
+#include <memory>
#include <algorithm>
+#include "base/optional.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
#include "third_party/blink/renderer/core/aom/accessible_node.h"
+#include "third_party/blink/renderer/core/css/css_resolution_units.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
@@ -79,6 +82,7 @@
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
+#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
@@ -87,6 +91,8 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_view.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/loader/progress_tracker.h"
#include "third_party/blink/renderer/core/mathml_names.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
@@ -1089,32 +1095,6 @@ bool AXNodeObject::IsTextControl() const {
return false;
}
-AXObject* AXNodeObject::MenuButtonForMenu() const {
- Element* menu_item = MenuItemElementForMenu();
-
- if (menu_item) {
- // ARIA just has generic menu items. AppKit needs to know if this is a top
- // level items like MenuBarButton or MenuBarItem
- AXObject* menu_item_ax = AXObjectCache().GetOrCreate(menu_item);
- if (menu_item_ax && menu_item_ax->IsMenuButton())
- return menu_item_ax;
- }
- return nullptr;
-}
-
-AXObject* AXNodeObject::MenuButtonForMenuIfExists() const {
- Element* menu_item = MenuItemElementForMenu();
-
- if (menu_item) {
- // ARIA just has generic menu items. AppKit needs to know if this is a top
- // level items like MenuBarButton or MenuBarItem
- AXObject* menu_item_ax = AXObjectCache().Get(menu_item);
- if (menu_item_ax && menu_item_ax->IsMenuButton())
- return menu_item_ax;
- }
- return nullptr;
-}
-
static Element* SiblingWithAriaRole(String role, Node* node) {
Node* parent = LayoutTreeBuilderTraversal::Parent(*node);
if (!parent)
@@ -1671,31 +1651,9 @@ String AXNodeObject::AutoComplete() const {
return String();
}
-namespace {
-
-bool MarkerTypeIsUsedForAccessibility(DocumentMarker::MarkerType type) {
- return DocumentMarker::MarkerTypes(
- DocumentMarker::kSpelling | DocumentMarker::kGrammar |
- DocumentMarker::kTextMatch | DocumentMarker::kActiveSuggestion |
- DocumentMarker::kSuggestion | DocumentMarker::kTextFragment)
- .Contains(type);
-}
-
-base::Optional<DocumentMarker::MarkerType> GetAriaSpellingOrGrammarMarker(
- const AXObject& obj) {
- const AtomicString& attribute_value =
- obj.GetAOMPropertyOrARIAAttribute(AOMStringProperty::kInvalid);
- if (EqualIgnoringASCIICase(attribute_value, "spelling"))
- return DocumentMarker::kSpelling;
- else if (EqualIgnoringASCIICase(attribute_value, "grammar"))
- return DocumentMarker::kGrammar;
- return base::nullopt;
-}
-
-} // namespace
-
-void AXNodeObject::Markers(Vector<DocumentMarker::MarkerType>& marker_types,
- Vector<AXRange>& marker_ranges) const {
+void AXNodeObject::GetDocumentMarkers(
+ Vector<DocumentMarker::MarkerType>* marker_types,
+ Vector<AXRange>* marker_ranges) const {
if (!GetNode() || !GetDocument() || !GetDocument()->View())
return;
@@ -1704,34 +1662,23 @@ void AXNodeObject::Markers(Vector<DocumentMarker::MarkerType>& marker_types,
return;
// First use ARIA markers for spelling/grammar if available.
- // As an optimization, only checks until the nearest block-like ancestor.
- AXObject* ax_ancestor = ParentObjectUnignored();
- base::Optional<DocumentMarker::MarkerType> aria_marker;
- while (ax_ancestor) {
- aria_marker = GetAriaSpellingOrGrammarMarker(*ax_ancestor);
- if (aria_marker)
- break; // Result obtained.
- if (ax_ancestor->GetNode()) {
- if (const ComputedStyle* style =
- ax_ancestor->GetNode()->GetComputedStyle()) {
- if (style->IsDisplayBlockContainer())
- break; // Do not go higher than block container.
- }
- }
- ax_ancestor = ax_ancestor->ParentObjectUnignored();
- }
- if (aria_marker) {
- marker_types.push_back(aria_marker.value());
- marker_ranges.push_back(AXRange::RangeOfContents(*this));
+ base::Optional<DocumentMarker::MarkerType> aria_marker_type =
+ GetAriaSpellingOrGrammarMarker();
+ if (aria_marker_type) {
+ marker_types->push_back(aria_marker_type.value());
+ marker_ranges->push_back(AXRange::RangeOfContents(*this));
}
DocumentMarkerController& marker_controller = GetDocument()->Markers();
- DocumentMarkerVector markers = marker_controller.MarkersFor(*text_node);
- for (DocumentMarker* marker : markers) {
- if (!MarkerTypeIsUsedForAccessibility(marker->GetType()) ||
- aria_marker == marker->GetType()) {
+ const DocumentMarker::MarkerTypes markers_used_by_accessibility(
+ DocumentMarker::kSpelling | DocumentMarker::kGrammar |
+ DocumentMarker::kTextMatch | DocumentMarker::kActiveSuggestion |
+ DocumentMarker::kSuggestion | DocumentMarker::kTextFragment);
+ const DocumentMarkerVector markers =
+ marker_controller.MarkersFor(*text_node, markers_used_by_accessibility);
+ for (const DocumentMarker* marker : markers) {
+ if (aria_marker_type == marker->GetType())
continue;
- }
const Position start_position(*GetNode(), marker->StartOffset());
const Position end_position(*GetNode(), marker->EndOffset());
@@ -1740,8 +1687,8 @@ void AXNodeObject::Markers(Vector<DocumentMarker::MarkerType>& marker_types,
continue;
}
- marker_types.push_back(marker->GetType());
- marker_ranges.emplace_back(
+ marker_types->push_back(marker->GetType());
+ marker_ranges->emplace_back(
AXPosition::FromPosition(start_position, TextAffinity::kDownstream,
AXPositionAdjustmentBehavior::kMoveLeft),
AXPosition::FromPosition(end_position, TextAffinity::kDownstream,
@@ -1760,9 +1707,6 @@ AXObject* AXNodeObject::InPageLinkTarget() const {
KURL link_url = anchor->HrefURL();
if (!link_url.IsValid())
return AXObject::InPageLinkTarget();
- String fragment = link_url.FragmentIdentifier();
- if (fragment.IsEmpty())
- return AXObject::InPageLinkTarget();
KURL document_url = GetDocument()->Url();
if (!document_url.IsValid() ||
@@ -1770,8 +1714,9 @@ AXObject* AXNodeObject::InPageLinkTarget() const {
return AXObject::InPageLinkTarget();
}
+ String fragment = link_url.FragmentIdentifier();
TreeScope& tree_scope = anchor->GetTreeScope();
- Element* target = tree_scope.FindAnchor(fragment);
+ Node* target = tree_scope.FindAnchor(fragment);
if (!target)
return AXObject::InPageLinkTarget();
// If the target is not in the accessibility tree, get the first unignored
@@ -1896,7 +1841,8 @@ String AXNodeObject::GetText() const {
}
ax::mojom::blink::TextAlign AXNodeObject::GetTextAlign() const {
- if (!GetLayoutObject())
+ // Object attributes are not applied to text objects.
+ if (IsTextObject() || !GetLayoutObject())
return ax::mojom::blink::TextAlign::kNone;
const ComputedStyle* style = GetLayoutObject()->Style();
@@ -1920,6 +1866,22 @@ ax::mojom::blink::TextAlign AXNodeObject::GetTextAlign() const {
}
}
+float AXNodeObject::GetTextIndent() const {
+ // Text-indent applies to lines or blocks, but not text.
+ if (IsTextObject() || !GetLayoutObject())
+ return 0.0f;
+ const ComputedStyle* style = GetLayoutObject()->Style();
+ if (!style)
+ return 0.0f;
+
+ const blink::LayoutBlock* layout_block =
+ GetLayoutObject()->InclusiveContainingBlock();
+ if (!layout_block)
+ return 0.0f;
+ float text_indent = layout_block->TextIndentOffset().ToFloat();
+ return text_indent / kCssPixelsPerMillimeter;
+}
+
String AXNodeObject::ImageDataUrl(const IntSize& max_size) const {
Node* node = GetNode();
if (!node)
@@ -1944,7 +1906,8 @@ String AXNodeObject::ImageDataUrl(const IntSize& max_size) const {
if (!bitmap_image)
return String();
- sk_sp<SkImage> image = bitmap_image->PaintImageForCurrentFrame().GetSkImage();
+ sk_sp<SkImage> image =
+ bitmap_image->PaintImageForCurrentFrame().GetSwSkImage();
if (!image || image->width() <= 0 || image->height() <= 0)
return String();
@@ -1962,12 +1925,18 @@ String AXNodeObject::ImageDataUrl(const IntSize& max_size) const {
int width = std::round(image->width() * scale);
int height = std::round(image->height() * scale);
- // Draw the scaled image into a bitmap in native format.
+ // Draw the image into a bitmap in native format.
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
- SkCanvas canvas(bitmap);
- canvas.clear(SK_ColorTRANSPARENT);
- canvas.drawImageRect(image, SkRect::MakeIWH(width, height), nullptr);
+ SkPixmap unscaled_pixmap;
+ if (scale == 1.0 && image->peekPixels(&unscaled_pixmap)) {
+ bitmap.installPixels(unscaled_pixmap);
+ } else {
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
+ SkCanvas canvas(bitmap);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.drawImageRect(image, SkRect::MakeIWH(width, height), nullptr);
+ }
// Copy the bits into a buffer in RGBA_8888 unpremultiplied format
// for encoding.
@@ -2689,14 +2658,8 @@ String AXNodeObject::TextAlternative(bool recursive,
return String();
}
- String text_alternative = AriaTextAlternative(
- recursive, in_aria_labelled_by_traversal, visited, name_from,
- related_objects, name_sources, &found_text_alternative);
- if (found_text_alternative && !name_sources)
- return text_alternative;
-
// Step 2E from: http://www.w3.org/TR/accname-aam-1.1 -- value from control
- if (recursive && !in_aria_labelled_by_traversal && CanSetValueAttribute()) {
+ if (recursive && CanSetValueAttribute()) {
// No need to set any name source info in a recursive call.
if (IsTextControl())
return GetText();
@@ -2729,6 +2692,12 @@ String AXNodeObject::TextAlternative(bool recursive,
return accumulated_text.ToString();
}
+ String text_alternative = AriaTextAlternative(
+ recursive, in_aria_labelled_by_traversal, visited, name_from,
+ related_objects, name_sources, &found_text_alternative);
+ if (found_text_alternative && !name_sources)
+ return text_alternative;
+
// Step 2D from: http://www.w3.org/TR/accname-aam-1.1
text_alternative =
NativeTextAlternative(visited, name_from, related_objects, name_sources,
@@ -2894,21 +2863,21 @@ String AXNodeObject::TextFromDescendants(AXObjectSet& visited,
bool is_continuation = child->GetLayoutObject() &&
child->GetLayoutObject()->IsElementContinuation();
- // Don't recurse into children that are explicitly marked as aria-hidden.
- // Note that we don't call isInertOrAriaHidden because that would return
+ // Don't recurse into children that are explicitly hidden.
+ // Note that we don't call IsInertOrAriaHidden because that would return
// true if any ancestor is hidden, but we need to be able to compute the
// accessible name of object inside hidden subtrees (for example, if
// aria-labelledby points to an object that's hidden).
if (!is_continuation &&
- child->AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty::kHidden))
+ (child->AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty::kHidden) ||
+ child->IsHiddenForTextAlternativeCalculation()))
continue;
ax::mojom::blink::NameFrom child_name_from =
ax::mojom::blink::NameFrom::kUninitialized;
String result;
if (!is_continuation && child->IsPresentational()) {
- if (child->IsVisible())
- result = child->TextFromDescendants(visited, true);
+ result = child->TextFromDescendants(visited, true);
} else {
result =
RecursiveTextAlternative(*child, false, visited, child_name_from);
@@ -3124,6 +3093,79 @@ void AXNodeObject::AddTableChildren() {
}
}
+int AXNodeObject::TextOffsetInFormattingContext(int offset) const {
+ DCHECK_GE(offset, 0);
+ if (IsDetached())
+ return 0;
+
+ // When a node has the first-letter CSS style applied to it, it is split into
+ // two parts (two branches) in the layout tree. The "first-letter part"
+ // contains its first letter and any surrounding Punctuation. The "remaining
+ // part" contains the rest of the text.
+ //
+ // We need to ensure that we retrieve the correct layout object: either the
+ // one for the "first-letter part" or the one for the "remaining part",
+ // depending of the value of |offset|.
+ const LayoutObject* layout_obj =
+ GetNode() ? AssociatedLayoutObjectOf(*GetNode(), offset)
+ : GetLayoutObject();
+ if (!layout_obj)
+ return AXObject::TextOffsetInFormattingContext(offset);
+
+ // We support calculating the text offset from the start of the formatting
+ // contexts of the following layout objects, provided that they are at
+ // inline-level, (display=inline) or "display=inline-block":
+ //
+ // (Note that in the following examples, the paragraph is the formatting
+ // context.
+ //
+ // Layout replaced, e.g. <p><img></p>.
+ // Layout inline with a layout text child, e.g. <p><a href="#">link</a></p>.
+ // Layout block flow, e.g. <p><b style="display: inline-block;"></b></p>.
+ // Layout text, e.g. <p>Hello</p>.
+ // Layout br (subclass of layout text), e.g. <p><br></p>.
+
+ if (layout_obj->IsLayoutInline()) {
+ // The NGOffsetMapping class doesn't map layout inline objects to their text
+ // mappings because such an operation could be ambiguous. An inline object
+ // may have another inline object inside it. For example,
+ // <span><span>Inner</span outer</span>. We need to recursively retrieve the
+ // first layout text or layout replaced child so that any potential
+ // ambiguity would be removed.
+ const AXObject* first_child = FirstChildIncludingIgnored();
+ return first_child ? first_child->TextOffsetInFormattingContext(offset)
+ : offset;
+ }
+
+ // TODO(crbug.com/567964): LayoutObject::IsAtomicInlineLevel() also includes
+ // block-level replaced elements. We need to explicitly exclude them via
+ // LayoutObject::IsInline().
+ const bool is_atomic_inline_level =
+ layout_obj->IsInline() && layout_obj->IsAtomicInlineLevel();
+ if (!is_atomic_inline_level && !layout_obj->IsText()) {
+ // Not in a formatting context in which text offsets are meaningful.
+ return AXObject::TextOffsetInFormattingContext(offset);
+ }
+
+ LayoutBlockFlow* formatting_context =
+ NGOffsetMapping::GetInlineFormattingContextOf(*layout_obj);
+ if (!formatting_context || formatting_context == layout_obj)
+ return AXObject::TextOffsetInFormattingContext(offset);
+
+ // If "formatting_context" is not a Layout NG object, the offset mappings will
+ // be computed on demand and cached.
+ const NGOffsetMapping* inline_offset_mapping =
+ NGInlineNode::GetOffsetMapping(formatting_context);
+ if (!inline_offset_mapping)
+ return AXObject::TextOffsetInFormattingContext(offset);
+
+ const base::span<const NGOffsetMappingUnit> mapping_units =
+ inline_offset_mapping->GetMappingUnitsForLayoutObject(*layout_obj);
+ if (mapping_units.empty())
+ return AXObject::TextOffsetInFormattingContext(offset);
+ return int{mapping_units.front().TextContentStart()} + offset;
+}
+
//
// Inline text boxes.
//
@@ -3392,15 +3434,13 @@ void AXNodeObject::InsertChild(AXObject* child, unsigned index) {
if (!child || !CanHaveChildren())
return;
- // If the parent is asking for this child's children, then either it's the
- // first time (and clearing is a no-op), or its visibility has changed. In
- // the latter case, this child may have a stale child cached. This can
- // prevent aria-hidden changes from working correctly. Hence, whenever a
- // parent is getting children, ensure data is not stale.
- child->ClearChildren();
-
if (!child->AccessibilityIsIncludedInTree()) {
- // Re-computes child's children.
+ // Child is ignored and not in the tree.
+ // Recompute the child's children now as we skip over the ignored object.
+ child->SetNeedsToUpdateChildren();
+ // Get the ignored child's children and add to children of ancestor
+ // included in tree. This will recurse if necessary, skipping levels of
+ // unignored descendants as it goes.
const auto& children = child->ChildrenIncludingIgnored();
wtf_size_t length = children.size();
for (wtf_size_t i = 0; i < length; ++i)
@@ -3426,11 +3466,19 @@ bool AXNodeObject::CanHaveChildren() const {
if (GetNode() && IsA<HTMLMapElement>(GetNode()))
return false; // Does not have a role, so check here
+ // Placeholder gets exposed as an attribute on the input accessibility node,
+ // so there's no need to add its text children. Placeholder text is a separate
+ // node that gets removed when it disappears, so this will only be present if
+ // the placeholder is visible.
+ if (GetElement() && GetElement()->ShadowPseudoId() ==
+ shadow_element_names::kPseudoInputPlaceholder) {
+ return false;
+ }
+
switch (native_role_) {
case ax::mojom::blink::Role::kCheckBox:
case ax::mojom::blink::Role::kImage:
case ax::mojom::blink::Role::kListBoxOption:
- case ax::mojom::blink::Role::kMenuButton:
case ax::mojom::blink::Role::kMenuListOption:
case ax::mojom::blink::Role::kMenuItem:
case ax::mojom::blink::Role::kMenuItemCheckBox:
@@ -3460,7 +3508,6 @@ bool AXNodeObject::CanHaveChildren() const {
case ax::mojom::blink::Role::kCheckBox:
case ax::mojom::blink::Role::kListBoxOption:
case ax::mojom::blink::Role::kMath: // role="math" is flat, unlike <math>
- case ax::mojom::blink::Role::kMenuButton:
case ax::mojom::blink::Role::kMenuListOption:
case ax::mojom::blink::Role::kMenuItem:
case ax::mojom::blink::Role::kMenuItemCheckBox:
@@ -3738,14 +3785,21 @@ void AXNodeObject::ChildrenChanged() {
// because unignored nodes recursively include all children of ignored
// nodes. This method is called during layout, so we need to be careful to
// only explore existing objects.
- AXObject* node_to_update = this;
- while (node_to_update) {
- node_to_update->SetNeedsToUpdateChildren();
- if (!node_to_update->LastKnownIsIgnoredValue())
- break;
- node_to_update = node_to_update->ParentObjectIfExists();
+ if (!LastKnownIsIncludedInTreeValue()) {
+ // The first object (this or ancestor) that is included in the tree is the
+ // one whose children may have changed.
+ // Can be null, e.g. if <title> contents change
+ if (ParentObjectIncludedInTree())
+ ParentObjectIncludedInTree()->SetNeedsToUpdateChildren();
}
+ // Also update the current object, in case it wasn't included in the tree but
+ // now is. In that case, the LastKnownIsIncludedInTreeValue() won't have been
+ // updated yet, so we can't use that. Unfortunately, this is not a safe time
+ // to get the current included in tree value, therefore, we'll play it safe
+ // and update the children in two places sometimes.
+ SetNeedsToUpdateChildren();
+
// If this node's children are not part of the accessibility tree then
// skip notification and walking up the ancestors.
// Cases where this happens:
@@ -3762,41 +3816,6 @@ void AXNodeObject::ChildrenChanged() {
AXObjectCache().PostNotification(this,
ax::mojom::blink::Event::kChildrenChanged);
-
- // Go up the accessibility parent chain, but only if the element already
- // exists. This method is called during layout, minimal work should be done.
- // If AX elements are created now, they could interrogate the layout tree
- // while it's in a funky state. At the same time, process ARIA live region
- // changes.
- for (AXObject* parent = this; parent;
- parent = parent->ParentObjectIfExists()) {
- // These notifications always need to be sent because screenreaders are
- // reliant on them to perform. In other words, they need to be sent even
- // when the screen reader has not accessed this live region since the last
- // update.
-
- // If this element supports ARIA live regions, then notify the AT of
- // changes. Do not fire live region changed events if aria-live="off".
- if (parent->IsLiveRegionRoot()) {
- if (parent->IsActiveLiveRegionRoot()) {
- AXObjectCache().PostNotification(
- parent, ax::mojom::blink::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()) {
- AXObjectCache().PostNotification(parent,
- ax::mojom::blink::Event::kValueChanged);
- break;
- }
- }
}
void AXNodeObject::UpdateChildrenIfNecessary() {
@@ -3854,41 +3873,6 @@ void AXNodeObject::SelectionChanged() {
}
}
-void AXNodeObject::TextChanged() {
- // If this element supports ARIA live regions, or is part of a region with an
- // ARIA editable role, then notify the AT of changes.
- AXObjectCacheImpl& cache = AXObjectCache();
- for (Node* parent_node = GetNode(); parent_node;
- parent_node = parent_node->parentNode()) {
- AXObject* parent = cache.Get(parent_node);
- if (!parent)
- continue;
-
- if (parent->IsLiveRegionRoot()) {
- if (parent->IsActiveLiveRegionRoot()) {
- cache.PostNotification(parent_node,
- ax::mojom::blink::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.
- 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::blink::Event::kValueChanged);
- break;
- }
- }
-}
-
AXObject* AXNodeObject::ErrorMessage() const {
// Check for aria-errormessage.
Element* existing_error_message =
@@ -4438,15 +4422,20 @@ String AXNodeObject::NativeTextAlternative(
}
}
- name_from = ax::mojom::blink::NameFrom::kRelatedElement;
+ text_alternative = document->title();
+ bool is_empty_title_element =
+ text_alternative.IsEmpty() && document->TitleElement();
+ if (is_empty_title_element)
+ name_from = ax::mojom::blink::NameFrom::kAttributeExplicitlyEmpty;
+ else
+ name_from = ax::mojom::blink::NameFrom::kRelatedElement;
+
if (name_sources) {
name_sources->push_back(NameSource(*found_text_alternative));
name_sources->back().type = name_from;
name_sources->back().native_source = kAXTextFromNativeHTMLTitleElement;
}
- text_alternative = document->title();
-
Element* title_element = document->TitleElement();
AXObject* title_ax_object = AXObjectCache().GetOrCreate(title_element);
if (title_ax_object) {
@@ -4577,19 +4566,16 @@ String AXNodeObject::Description(
// aria-description overrides any HTML-based accessible description,
// but not aria-describedby.
- if (RuntimeEnabledFeatures::AccessibilityExposeARIAAnnotationsEnabled(
- element->GetExecutionContext())) {
- const AtomicString& aria_desc =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kDescription);
- if (!aria_desc.IsNull()) {
- description_from = ax::mojom::blink::DescriptionFrom::kAttribute;
- description = aria_desc;
- if (description_sources) {
- found_description = true;
- description_sources->back().text = description;
- } else {
- return description;
- }
+ const AtomicString& aria_desc =
+ GetAOMPropertyOrARIAAttribute(AOMStringProperty::kDescription);
+ if (!aria_desc.IsNull()) {
+ description_from = ax::mojom::blink::DescriptionFrom::kAttribute;
+ description = aria_desc;
+ if (description_sources) {
+ found_description = true;
+ description_sources->back().text = description;
+ } else {
+ return description;
}
}
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 1a0c7b7bdcf..0538e45266c 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
@@ -30,6 +30,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_NODE_OBJECT_H_
#include "base/macros.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -74,8 +75,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool HasContentEditableAttributeSet() const;
bool IsTextControl() const override;
- AXObject* MenuButtonForMenu() const;
- AXObject* MenuButtonForMenuIfExists() const;
Element* MenuItemElementForMenu() const;
Element* MouseButtonListener() const;
bool IsNativeCheckboxOrRadio() const;
@@ -138,17 +137,21 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool CanvasHasFallbackContent() const final;
int HeadingLevel() const final;
unsigned HierarchicalLevel() const final;
- void Markers(Vector<DocumentMarker::MarkerType>&,
- Vector<AXRange>&) const override;
+ void GetDocumentMarkers(Vector<DocumentMarker::MarkerType>* marker_types,
+ Vector<AXRange>* marker_ranges) const override;
AXObject* InPageLinkTarget() const override;
AccessibilityOrientation Orientation() const override;
AXObjectVector RadioButtonsInGroup() const override;
static HeapVector<Member<HTMLInputElement>> FindAllRadioButtonsWithSameName(
HTMLInputElement* radio_button);
String GetText() const override;
- ax::mojom::blink::TextAlign GetTextAlign() const final;
String ImageDataUrl(const IntSize& max_size) const final;
int TextLength() const override;
+ int TextOffsetInFormattingContext(int offset) const override;
+
+ // Object attributes.
+ ax::mojom::blink::TextAlign GetTextAlign() const final;
+ float GetTextIndent() const final;
// Properties of interactive elements.
ax::mojom::blink::AriaCurrentState GetAriaCurrentState() const final;
@@ -247,7 +250,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
// Notifications that this object may have changed.
void ChildrenChanged() override;
void SelectionChanged() final;
- void TextChanged() override;
// The aria-errormessage object or native object from a validationMessage
// alert.
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object_test.cc
new file mode 100644
index 00000000000..44a2703c697
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object_test.cc
@@ -0,0 +1,170 @@
+// Copyright 2020 The Chromium Authors. 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_node_object.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h"
+
+namespace blink {
+namespace test {
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutReplaced) {
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before <img id="replaced" alt="alt"> after.
+ </p>)HTML");
+
+ const AXObject* ax_replaced = GetAXObjectByElementId("replaced");
+ ASSERT_NE(nullptr, ax_replaced);
+ ASSERT_EQ(ax::mojom::Role::kImage, ax_replaced->RoleValue());
+ ASSERT_EQ("alt", ax_replaced->ComputedName());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_replaced->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_replaced->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutInline) {
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before <a id="inline" href="#">link</a> after.
+ </p>)HTML");
+
+ const AXObject* ax_inline = GetAXObjectByElementId("inline");
+ ASSERT_NE(nullptr, ax_inline);
+ ASSERT_EQ(ax::mojom::Role::kLink, ax_inline->RoleValue());
+ ASSERT_EQ("link", ax_inline->ComputedName());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_inline->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_inline->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutBlockFlowAtInlineLevel) {
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before
+ <b id="block-flow" style="display: inline-block;">block flow</b>
+ after.
+ </p>)HTML");
+
+ const AXObject* ax_block_flow = GetAXObjectByElementId("block-flow");
+ ASSERT_NE(nullptr, ax_block_flow);
+ ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_block_flow->RoleValue());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_block_flow->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_block_flow->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutBlockFlowAtBlockLevel) {
+ // NGOffsetMapping does not support block flow objects that are at
+ // block-level, so we do not support them as well.
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before
+ <b id="block-flow" style="display: block;">block flow</b>
+ after.
+ </p>)HTML");
+
+ const AXObject* ax_block_flow = GetAXObjectByElementId("block-flow");
+ ASSERT_NE(nullptr, ax_block_flow);
+ ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_block_flow->RoleValue());
+ // Since block-level elements do not expose a count of the number of
+ // characters from the beginning of their formatting context, we return the
+ // same offset that was passed in.
+ EXPECT_EQ(0, ax_block_flow->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(1, ax_block_flow->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutText) {
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before <span id="span">text</span> after.
+ </p>)HTML");
+
+ const AXObject* ax_text =
+ GetAXObjectByElementId("span")->FirstChildIncludingIgnored();
+ ASSERT_NE(nullptr, ax_text);
+ ASSERT_EQ(ax::mojom::Role::kStaticText, ax_text->RoleValue());
+ ASSERT_EQ("text", ax_text->ComputedName());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_text->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_text->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutBr) {
+ SetBodyInnerHTML(R"HTML(
+ <p>
+ Before <br id="br"> after.
+ </p>)HTML");
+
+ const AXObject* ax_br = GetAXObjectByElementId("br");
+ ASSERT_NE(nullptr, ax_br);
+ ASSERT_EQ(ax::mojom::Role::kLineBreak, ax_br->RoleValue());
+ ASSERT_EQ("\n", ax_br->ComputedName());
+ // After white space is compressed, the word "before" is of length 6.
+ EXPECT_EQ(6, ax_br->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(7, ax_br->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithLayoutFirstLetter) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ q::first-letter {
+ color: red;
+ }
+ </style>
+ <p>
+ Before
+ <q id="first-letter">1. Remaining part</q>
+ after.
+ </p>)HTML");
+
+ const AXObject* ax_first_letter = GetAXObjectByElementId("first-letter");
+ ASSERT_NE(nullptr, ax_first_letter);
+ ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_first_letter->RoleValue());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_first_letter->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_first_letter->TextOffsetInFormattingContext(1));
+}
+
+TEST_P(ParameterizedAccessibilityTest,
+ TextOffsetInFormattingContextWithCSSGeneratedContent) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ q::before {
+ content: "<";
+ color: blue;
+ }
+ q::after {
+ content: ">";
+ color: red;
+ }
+ </style>
+ <p>
+ Before <q id="css-generated">CSS generated</q> after.
+ </p>)HTML");
+
+ const AXObject* ax_css_generated = GetAXObjectByElementId("css-generated");
+ ASSERT_NE(nullptr, ax_css_generated);
+ ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_css_generated->RoleValue());
+ // After white space is compressed, the word "before" plus a single white
+ // space is of length 7.
+ EXPECT_EQ(7, ax_css_generated->TextOffsetInFormattingContext(0));
+ EXPECT_EQ(8, ax_css_generated->TextOffsetInFormattingContext(1));
+}
+
+} // namespace test
+} // namespace blink
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 7f73b349806..ba6c3093280 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -29,8 +29,8 @@
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include <algorithm>
-
-#include "third_party/blink/public/common/features.h"
+#include "base/strings/string_util.h"
+#include "third_party/blink/public/common/input/web_menu_source_type.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
#include "third_party/blink/renderer/core/aom/accessible_node.h"
#include "third_party/blink/renderer/core/aom/accessible_node_list.h"
@@ -68,7 +68,7 @@
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/accessibility/ax_range.h"
#include "third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.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/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/text/platform_locale.h"
@@ -383,7 +383,6 @@ const InternalRoleEntry kInternalRoles[] = {
{ax::mojom::blink::Role::kMarquee, "Marquee"},
{ax::mojom::blink::Role::kMath, "Math"},
{ax::mojom::blink::Role::kMenuBar, "MenuBar"},
- {ax::mojom::blink::Role::kMenuButton, "MenuButton"},
{ax::mojom::blink::Role::kMenuItem, "MenuItem"},
{ax::mojom::blink::Role::kMenuItemCheckBox, "MenuItemCheckBox"},
{ax::mojom::blink::Role::kMenuItemRadio, "MenuItemRadio"},
@@ -459,7 +458,6 @@ const RoleEntry kReverseRoles[] = {
{"button", ax::mojom::blink::Role::kToggleButton},
{"combobox", ax::mojom::blink::Role::kPopUpButton},
{"contentinfo", ax::mojom::blink::Role::kFooter},
- {"menuitem", ax::mojom::blink::Role::kMenuButton},
{"menuitem", ax::mojom::blink::Role::kMenuListOption},
{"progressbar", ax::mojom::blink::Role::kMeter},
{"region", ax::mojom::blink::Role::kSection},
@@ -512,6 +510,17 @@ HTMLDialogElement* GetActiveDialogElement(Node* node) {
return node->GetDocument().ActiveModalDialog();
}
+bool HasUninheritedHiddenVisibility(const ComputedStyle* style, Node* node) {
+ // Is this the root of a visibility:hidden or visibility:collapsed subtree?
+ if (style->Visibility() == EVisibility::kVisible)
+ return false;
+ Node* parent = node->parentNode();
+ if (!parent)
+ return true;
+ return !parent->GetComputedStyle() ||
+ parent->GetComputedStyle()->Visibility() == EVisibility::kVisible;
+}
+
} // namespace
unsigned AXObject::number_of_live_ax_objects_ = 0;
@@ -521,6 +530,8 @@ AXObject::AXObject(AXObjectCacheImpl& ax_object_cache)
have_children_(false),
role_(ax::mojom::blink::Role::kUnknown),
aria_role_(ax::mojom::blink::Role::kUnknown),
+ last_known_is_ignored_value_(kDefaultBehavior),
+ last_known_is_ignored_but_included_in_tree_value_(kDefaultBehavior),
explicit_container_id_(0),
parent_(nullptr),
last_modification_count_(-1),
@@ -545,7 +556,6 @@ AXObject::~AXObject() {
void AXObject::Init() {
role_ = DetermineAccessibilityRole();
- UpdateCachedAttributeValuesIfNeeded();
}
void AXObject::Detach() {
@@ -728,7 +738,8 @@ void AXObject::GetSparseAXAttributes(
}
}
-void AXObject::Serialize(ui::AXNodeData* node_data) {
+void AXObject::Serialize(ui::AXNodeData* node_data,
+ ui::AXMode accessibility_mode) {
AccessibilityExpanded expanded = IsExpanded();
if (expanded) {
if (expanded == kExpandedCollapsed)
@@ -812,6 +823,11 @@ void AXObject::Serialize(ui::AXNodeData* node_data) {
node_data->SetTextAlign(GetTextAlign());
}
+ if (GetTextIndent() != 0.0f) {
+ node_data->AddFloatAttribute(ax::mojom::blink::FloatAttribute::kTextIndent,
+ GetTextIndent());
+ }
+
// If this is an HTMLFrameOwnerElement (such as an iframe), we may need
// to embed the ID of the child frame.
if (auto* html_frame_owner_element =
@@ -826,6 +842,157 @@ void AXObject::Serialize(ui::AXNodeData* node_data) {
}
}
}
+
+ if (accessibility_mode.has_mode(ui::AXMode::kScreenReader) ||
+ accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+ // The DOMNodeID from Blink. Currently only populated when using
+ // the accessibility tree for PDF exporting. Warning, this is totally
+ // unrelated to the accessibility node ID, or the ID attribute for an
+ // HTML element - it's an ID used to uniquely identify nodes in Blink.
+ int dom_node_id = GetDOMNodeId();
+ if (dom_node_id) {
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kDOMNodeId,
+ dom_node_id);
+ }
+
+ SerializeTableAttributes(node_data);
+ }
+
+ if (accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+ // Return early. None of the following attributes are needed for PDFs.
+ return;
+ }
+
+ if (ValueDescription().length()) {
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kValue,
+ ValueDescription().Utf8());
+ } else {
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kValue,
+ StringValue().Utf8());
+ }
+
+ switch (Restriction()) {
+ case AXRestriction::kRestrictionReadOnly:
+ node_data->SetRestriction(ax::mojom::blink::Restriction::kReadOnly);
+ break;
+ case AXRestriction::kRestrictionDisabled:
+ node_data->SetRestriction(ax::mojom::blink::Restriction::kDisabled);
+ break;
+ case AXRestriction::kRestrictionNone:
+ if (CanSetValueAttribute())
+ node_data->AddAction(ax::mojom::blink::Action::kSetValue);
+ break;
+ }
+
+ if (!Url().IsEmpty()) {
+ TruncateAndAddStringAttribute(node_data,
+ ax::mojom::blink::StringAttribute::kUrl,
+ Url().GetString().Utf8());
+ }
+
+ SerializePartialSparseAttributes(node_data);
+}
+
+void AXObject::SerializeTableAttributes(ui::AXNodeData* node_data) {
+ if (ui::IsTableLike(RoleValue())) {
+ int aria_colcount = AriaColumnCount();
+ if (aria_colcount) {
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kAriaColumnCount, aria_colcount);
+ }
+ int aria_rowcount = AriaRowCount();
+ if (aria_rowcount) {
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kAriaRowCount,
+ aria_rowcount);
+ }
+ }
+
+ if (ui::IsTableRow(RoleValue())) {
+ AXObject* header = HeaderObject();
+ if (header && !header->IsDetached()) {
+ // TODO(accessibility): these should be computed by ui::AXTableInfo and
+ // removed here.
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kTableRowHeaderId,
+ header->AXObjectID());
+ }
+ }
+
+ if (ui::IsCellOrTableHeader(RoleValue())) {
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kTableCellColumnSpan, ColumnSpan());
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kTableCellRowSpan, RowSpan());
+ }
+
+ if (ui::IsCellOrTableHeader(RoleValue()) || ui::IsTableRow(RoleValue())) {
+ // aria-rowindex and aria-colindex are supported on cells, headers and
+ // rows.
+ int aria_rowindex = AriaRowIndex();
+ if (aria_rowindex) {
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kAriaCellRowIndex, aria_rowindex);
+ }
+
+ int aria_colindex = AriaColumnIndex();
+ if (aria_colindex) {
+ node_data->AddIntAttribute(
+ ax::mojom::blink::IntAttribute::kAriaCellColumnIndex, aria_colindex);
+ }
+ }
+
+ if (ui::IsTableHeader(RoleValue()) &&
+ GetSortDirection() != ax::mojom::blink::SortDirection::kNone) {
+ node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kSortDirection,
+ static_cast<int32_t>(GetSortDirection()));
+ }
+}
+
+void AXObject::SerializePartialSparseAttributes(ui::AXNodeData* node_data) {
+ Element* element = GetElement();
+ if (!element)
+ return;
+
+ TempSetterMap& setter_map = GetTempSetterMap(node_data);
+ AttributeCollection attributes = element->AttributesWithoutUpdate();
+ HashSet<QualifiedName> set_attributes;
+ for (const Attribute& attr : attributes) {
+ set_attributes.insert(attr.GetName());
+ AXSparseSetterFunc callback = setter_map.at(attr.GetName());
+
+ if (callback)
+ callback.Run(node_data, attr.Value());
+ }
+
+ if (!element->DidAttachInternals())
+ return;
+ const auto& internals_attributes =
+ element->EnsureElementInternals().GetAttributes();
+ for (const QualifiedName& attr : internals_attributes.Keys()) {
+ if (set_attributes.Contains(attr))
+ continue;
+
+ AXSparseSetterFunc callback = setter_map.at(attr);
+
+ if (callback)
+ callback.Run(node_data, internals_attributes.at(attr));
+ }
+}
+
+void AXObject::TruncateAndAddStringAttribute(
+ ui::AXNodeData* dst,
+ ax::mojom::blink::StringAttribute attribute,
+ const std::string& value,
+ uint32_t max_len) const {
+ if (value.size() > max_len) {
+ std::string truncated;
+ base::TruncateUTF8ToByteSize(value, max_len, &truncated);
+ dst->AddStringAttribute(attribute, truncated);
+ } else {
+ dst->AddStringAttribute(attribute, value);
+ }
}
bool AXObject::IsAXNodeObject() const {
@@ -970,10 +1137,6 @@ bool AXObject::IsMenu() const {
return RoleValue() == ax::mojom::blink::Role::kMenu;
}
-bool AXObject::IsMenuButton() const {
- return RoleValue() == ax::mojom::blink::Role::kMenuButton;
-}
-
bool AXObject::IsCheckable() const {
switch (RoleValue()) {
case ax::mojom::blink::Role::kCheckBox:
@@ -1184,29 +1347,36 @@ void AXObject::UpdateCachedAttributeValuesIfNeeded() const {
if (cache.ModificationCount() == last_modification_count_)
return;
+#if DCHECK_IS_ON() // Required in order to get Lifecycle().ToString()
+ DCHECK(!GetDocument() || GetDocument()->Lifecycle().GetState() >=
+ DocumentLifecycle::kAfterPerformLayout)
+ << "Unclean document at lifecycle "
+ << GetDocument()->Lifecycle().ToString();
+#endif
+
last_modification_count_ = cache.ModificationCount();
+
+ if (GetElement() && !GetLayoutObject() &&
+ !DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) {
+ // While it's safe to do so, ensure the computed style for display:none
+ // nodes, so that IsHiddenForTextAlternativeCalculation() can determine
+ // whether the node is directly styled as display:none vs hidden because
+ // of display:none on an ancestor.
+ // If there is no computed style, assume that it may be display:none,
+ // since we can't prove otherwise.
+ const ComputedStyle* style = GetElement()->GetComputedStyle();
+ if (!style || style->IsEnsuredInDisplayNone())
+ GetElement()->EnsureComputedStyle();
+ }
cached_background_color_ = ComputeBackgroundColor();
cached_is_inert_or_aria_hidden_ = ComputeIsInertOrAriaHidden();
cached_is_descendant_of_leaf_node_ = !!LeafNodeAncestor();
cached_is_descendant_of_disabled_node_ = !!DisabledAncestor();
cached_has_inherited_presentational_role_ =
!!InheritsPresentationalRoleFrom();
- bool is_ignored = ComputeAccessibilityIsIgnored();
- bool is_ignored_but_included_in_tree =
- is_ignored && ComputeAccessibilityIsIgnoredButIncludedInTree();
- bool ignored_states_changed = false;
- if (parent_) {
- // Do not compute ignored changed if no parent, because this is the first
- // time the object is being initialized, and because there are no
- // ancestors to call ChildrenChanged() on anyway.
- if (is_ignored != cached_is_ignored_ ||
- is_ignored_but_included_in_tree !=
- cached_is_ignored_but_included_in_tree_) {
- ignored_states_changed = true;
- }
- }
- cached_is_ignored_ = is_ignored;
- cached_is_ignored_but_included_in_tree_ = is_ignored_but_included_in_tree;
+ cached_is_ignored_ = ComputeAccessibilityIsIgnored();
+ cached_is_ignored_but_included_in_tree_ =
+ cached_is_ignored_ && ComputeAccessibilityIsIgnoredButIncludedInTree();
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".
@@ -1220,6 +1390,21 @@ void AXObject::UpdateCachedAttributeValuesIfNeeded() const {
cached_aria_column_index_ = ComputeAriaColumnIndex();
cached_aria_row_index_ = ComputeAriaRowIndex();
+ bool ignored_states_changed = false;
+ if (cached_is_ignored_ != LastKnownIsIgnoredValue()) {
+ last_known_is_ignored_value_ =
+ cached_is_ignored_ ? kIgnoreObject : kIncludeObject;
+ ignored_states_changed = true;
+ }
+
+ if (cached_is_ignored_but_included_in_tree_ !=
+ LastKnownIsIgnoredButIncludedInTreeValue()) {
+ last_known_is_ignored_but_included_in_tree_value_ =
+ cached_is_ignored_but_included_in_tree_ ? kIncludeObject
+ : kIgnoreObject;
+ ignored_states_changed = true;
+ }
+
if (ignored_states_changed) {
if (AXObject* parent = ParentObjectIfExists())
parent->ChildrenChanged();
@@ -1236,28 +1421,19 @@ bool AXObject::AccessibilityIsIgnoredByDefault(
return DefaultObjectInclusion(ignored_reasons) == kIgnoreObject;
}
-AXObjectInclusion AXObject::AccessibilityPlatformIncludesObject() const {
- if (IsA<AXMenuListPopup>(this) || IsA<AXMenuListOption>(this))
- return kIncludeObject;
-
- return kDefaultBehavior;
-}
-
AXObjectInclusion AXObject::DefaultObjectInclusion(
IgnoredReasons* ignored_reasons) const {
if (IsInertOrAriaHidden()) {
// Keep focusable elements that are aria-hidden in tree, so that they can
- // still fire events such as focus and value changes. Handle the case where
- // a <select> element is aria-hidden.
- if (RoleValue() != ax::mojom::blink::Role::kMenuListPopup &&
- !CanSetFocusAttribute()) {
+ // still fire events such as focus and value changes.
+ if (!CanSetFocusAttribute()) {
if (ignored_reasons)
ComputeIsInertOrAriaHidden(ignored_reasons);
return kIgnoreObject;
}
}
- return AccessibilityPlatformIncludesObject();
+ return kDefaultBehavior;
}
bool AXObject::IsInertOrAriaHidden() const {
@@ -1552,6 +1728,20 @@ bool AXObject::ComputeAccessibilityIsIgnoredButIncludedInTree() const {
return false;
}
+const AXObject* AXObject::GetNativeTextControlAncestor(
+ int max_levels_to_check) const {
+ if (IsNativeTextControl())
+ return this;
+
+ if (max_levels_to_check == 0)
+ return nullptr;
+
+ if (AXObject* parent = ParentObject())
+ return parent->GetNativeTextControlAncestor(max_levels_to_check - 1);
+
+ return nullptr;
+}
+
const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const {
switch (RoleValue()) {
case ax::mojom::blink::Role::kDateTime:
@@ -1573,11 +1763,37 @@ const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const {
}
bool AXObject::LastKnownIsIgnoredValue() const {
- return cached_is_ignored_;
+ if (last_known_is_ignored_value_ == kDefaultBehavior) {
+ last_known_is_ignored_value_ =
+ AccessibilityIsIgnored() ? kIgnoreObject : kIncludeObject;
+ }
+
+ return last_known_is_ignored_value_ == kIgnoreObject;
+}
+
+void AXObject::SetLastKnownIsIgnoredValue(bool is_ignored) {
+ last_known_is_ignored_value_ = is_ignored ? kIgnoreObject : kIncludeObject;
}
bool AXObject::LastKnownIsIgnoredButIncludedInTreeValue() const {
- return cached_is_ignored_but_included_in_tree_;
+ if (last_known_is_ignored_but_included_in_tree_value_ == kDefaultBehavior) {
+ last_known_is_ignored_but_included_in_tree_value_ =
+ AccessibilityIsIgnoredButIncludedInTree() ? kIncludeObject
+ : kIgnoreObject;
+ }
+
+ return last_known_is_ignored_but_included_in_tree_value_ == kIncludeObject;
+}
+
+void AXObject::SetLastKnownIsIgnoredButIncludedInTreeValue(
+ bool is_ignored_but_included_in_tree) {
+ last_known_is_ignored_but_included_in_tree_value_ =
+ is_ignored_but_included_in_tree ? kIncludeObject : kIgnoreObject;
+}
+
+bool AXObject::LastKnownIsIncludedInTreeValue() const {
+ return !LastKnownIsIgnoredValue() ||
+ LastKnownIsIgnoredButIncludedInTreeValue();
}
bool AXObject::HasInheritedPresentationalRole() const {
@@ -1779,7 +1995,7 @@ void AXObject::UpdateDistributionForFlatTreeTraversal() const {
}
bool AXObject::IsARIAControlledByTextboxWithActiveDescendant() const {
- if (IsDetached())
+ if (IsDetached() || !GetDocument())
return false;
// This situation should mostly arise when using an active descendant on a
@@ -1787,7 +2003,11 @@ bool AXObject::IsARIAControlledByTextboxWithActiveDescendant() const {
// option in a list. In such situations, the active descendant is useful only
// when the textbox is focused. Therefore, we don't currently need to keep
// track of all aria-controls relationships.
- const AXObject* focused_object = AXObjectCache().FocusedObject();
+ const Element* focused_element = GetDocument()->FocusedElement();
+ if (!focused_element)
+ return false;
+
+ const AXObject* focused_object = AXObjectCache().GetOrCreate(focused_element);
if (!focused_object || !focused_object->IsTextControl())
return false;
@@ -1909,18 +2129,12 @@ String AXObject::GetName(ax::mojom::blink::NameFrom& name_from,
AXObject::AXObjectVector* name_objects) const {
HeapHashSet<Member<const AXObject>> visited;
AXRelatedObjectVector related_objects;
- // For purposes of computing a text alternative, if an ignored node is
- // included in the tree, assume that it is the target of aria-labelledby or
- // aria-describedby, since we can't tell yet whether that's the case. If it
- // isn't exposed, the AT will never see the name anyways.
- bool hidden_and_ignored_but_included_in_tree =
- IsHiddenForTextAlternativeCalculation() &&
- AccessibilityIsIgnoredButIncludedInTree();
+
// Initialize |name_from|, as TextAlternative() might never set it in some
// cases.
name_from = ax::mojom::blink::NameFrom::kNone;
- String text = TextAlternative(false, hidden_and_ignored_but_included_in_tree,
- visited, name_from, &related_objects, nullptr);
+ String text = TextAlternative(false, false, visited, name_from,
+ &related_objects, nullptr);
ax::mojom::blink::Role role = RoleValue();
if (!GetNode() || (!IsA<HTMLBRElement>(GetNode()) &&
@@ -1941,16 +2155,8 @@ String AXObject::GetName(NameSources* name_sources) const {
AXObjectSet visited;
ax::mojom::blink::NameFrom tmp_name_from;
AXRelatedObjectVector tmp_related_objects;
- // For purposes of computing a text alternative, if an ignored node is
- // included in the tree, assume that it is the target of aria-labelledby or
- // aria-describedby, since we can't tell yet whether that's the case. If it
- // isn't exposed, the AT will never see the name anyways.
- bool hidden_and_ignored_but_included_in_tree =
- IsHiddenForTextAlternativeCalculation() &&
- AccessibilityIsIgnoredButIncludedInTree();
- String text =
- TextAlternative(false, hidden_and_ignored_but_included_in_tree, visited,
- tmp_name_from, &tmp_related_objects, name_sources);
+ String text = TextAlternative(false, false, visited, tmp_name_from,
+ &tmp_related_objects, name_sources);
text = text.SimplifyWhiteSpace(IsHTMLSpace<UChar>);
return text;
}
@@ -1995,6 +2201,15 @@ bool AXObject::IsHiddenViaStyle() const {
return false;
}
+// Return true if this should be removed from accessible name computations,
+// unless it is reached by following an aria-labelledby. When that happens, this
+// is not checked, because aria-labelledby can use hidden subtrees.
+// Because aria-labelledby can use hidden subtrees, when it has entered a hidden
+// subtree, it is not enough to check if the element was hidden by an ancestor.
+// In this case, return true only if the hiding style targeted the node
+// directly, as opposed to having inherited the hiding style. Using inherited
+// hiding styles is problematic because it would prevent name contributions from
+// deeper nodes in hidden aria-labelledby subtrees.
bool AXObject::IsHiddenForTextAlternativeCalculation() const {
if (AOMPropertyOrARIAAttributeIsFalse(AOMBooleanProperty::kHidden))
return false;
@@ -2007,30 +2222,31 @@ bool AXObject::IsHiddenForTextAlternativeCalculation() const {
if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node))
return false;
- if (GetLayoutObject())
- return GetLayoutObject()->Style()->Visibility() != EVisibility::kVisible;
+ Document* document = GetDocument();
+ if (!document || !document->GetFrame())
+ return false;
- if (IsA<HTMLNoScriptElement>(node))
+ if (GetLayoutObject()) {
+ return HasUninheritedHiddenVisibility(GetLayoutObject()->Style(),
+ GetNode());
+ } else if (GetNode() && IsA<HTMLNoScriptElement>(GetNode())) {
return true;
+ }
- // This is an obscure corner case: if a node has no LayoutObject, that means
+ // This is an important corner case: if a node has no LayoutObject, that means
// it's not rendered, but we still may be exploring it as part of a text
// alternative calculation, for example if it was explicitly referenced by
// aria-labelledby. So we need to explicitly call the style resolver to check
// whether it's invisible or display:none, rather than relying on the style
// cached in the LayoutObject.
- Document* document = GetDocument();
- if (!document || !document->GetFrame())
- return false;
-
auto* element = DynamicTo<Element>(node);
if (element && node->isConnected()) {
- const ComputedStyle* style = element->EnsureComputedStyle();
+ const ComputedStyle* style = element->GetComputedStyle();
if (!style)
return false;
if (style->Display() == EDisplay::kNone ||
- style->Visibility() != EVisibility::kVisible) {
+ HasUninheritedHiddenVisibility(style, GetNode())) {
return true;
}
@@ -2246,14 +2462,55 @@ AccessibilityOrientation AXObject::Orientation() const {
return kAccessibilityOrientationUndefined;
}
-void AXObject::Markers(Vector<DocumentMarker::MarkerType>&,
- Vector<AXRange>&) const {}
+void AXObject::LoadInlineTextBoxes() {}
+
+AXObject* AXObject::NextOnLine() const {
+ return nullptr;
+}
+
+AXObject* AXObject::PreviousOnLine() const {
+ return nullptr;
+}
+
+base::Optional<const DocumentMarker::MarkerType>
+AXObject::GetAriaSpellingOrGrammarMarker() const {
+ AtomicString aria_invalid_value;
+ const AncestorsIterator iter = std::find_if(
+ UnignoredAncestorsBegin(), UnignoredAncestorsEnd(),
+ [&aria_invalid_value](const AXObject& ancestor) {
+ return ancestor.HasAOMPropertyOrARIAAttribute(
+ AOMStringProperty::kInvalid, aria_invalid_value) ||
+ ancestor.IsLineBreakingObject();
+ });
+
+ if (iter == UnignoredAncestorsEnd())
+ return base::nullopt;
+ if (EqualIgnoringASCIICase(aria_invalid_value, "spelling"))
+ return DocumentMarker::kSpelling;
+ if (EqualIgnoringASCIICase(aria_invalid_value, "grammar"))
+ return DocumentMarker::kGrammar;
+ return base::nullopt;
+}
+
+void AXObject::GetDocumentMarkers(
+ VectorOf<DocumentMarker::MarkerType>* marker_types,
+ VectorOf<AXRange>* marker_ranges) const {}
void AXObject::TextCharacterOffsets(Vector<int>&) const {}
void AXObject::GetWordBoundaries(Vector<int>& word_starts,
Vector<int>& word_ends) const {}
+int AXObject::TextOffsetInFormattingContext(int offset) const {
+ DCHECK_GE(offset, 0);
+ return offset;
+}
+
+int AXObject::TextOffsetInContainer(int offset) const {
+ DCHECK_GE(offset, 0);
+ return offset;
+}
+
ax::mojom::blink::DefaultActionVerb AXObject::Action() const {
Element* action_element = ActionElement();
if (!action_element)
@@ -2322,7 +2579,6 @@ bool AXObject::SupportsARIAExpanded() const {
case ax::mojom::blink::Role::kListBox:
case ax::mojom::blink::Role::kLink:
case ax::mojom::blink::Role::kPopUpButton:
- case ax::mojom::blink::Role::kMenuButton:
case ax::mojom::blink::Role::kMenuItem:
case ax::mojom::blink::Role::kMenuItemCheckBox:
case ax::mojom::blink::Role::kMenuItemRadio:
@@ -2485,21 +2741,6 @@ ax::mojom::blink::Role AXObject::DetermineAriaRoleAttribute() const {
ax::mojom::blink::Role role = AriaRoleToWebCoreRole(aria_role);
- switch (role) {
- case ax::mojom::blink::Role::kComment:
- case ax::mojom::blink::Role::kMark:
- case ax::mojom::blink::Role::kSuggestion:
- UseCounter::Count(GetDocument(), WebFeature::kARIAAnnotations);
- if (GetElement() &&
- !RuntimeEnabledFeatures::AccessibilityExposeARIAAnnotationsEnabled(
- GetElement()->GetExecutionContext())) {
- role = ax::mojom::blink::Role::kGenericContainer;
- }
- break;
- default:
- break;
- }
-
// ARIA states if an item can get focus, it should not be presentational.
// It also states user agents should ignore the presentational role if
// the element has global ARIA states and properties.
@@ -2578,11 +2819,6 @@ ax::mojom::blink::Role AXObject::RemapAriaRoleDueToParent(
if (role == ax::mojom::blink::Role::kListBoxOption &&
parent_aria_role == ax::mojom::blink::Role::kMenu)
return ax::mojom::blink::Role::kMenuItem;
- // An aria "menuitem" may map to MenuButton or MenuItem depending on its
- // parent.
- if (role == ax::mojom::blink::Role::kMenuItem &&
- parent_aria_role == ax::mojom::blink::Role::kGroup)
- return ax::mojom::blink::Role::kMenuButton;
// If the parent had a different role, then we don't need to continue
// searching up the chain.
@@ -3500,11 +3736,16 @@ void AXObject::GetRelativeBounds(AXObject** out_container,
if (!layout_object)
return;
+ if (layout_object->IsFixedPositioned() ||
+ layout_object->IsStickyPositioned()) {
+ AXObjectCache().AddToFixedOrStickyNodeList(this);
+ }
+
if (clips_children) {
if (IsWebArea())
*clips_children = true;
else
- *clips_children = layout_object->HasOverflowClip();
+ *clips_children = layout_object->HasNonVisibleOverflow();
}
if (IsWebArea()) {
@@ -3879,7 +4120,8 @@ bool AXObject::OnNativeShowContextMenuAction() {
return false;
ContextMenuAllowedScope scope;
- document->GetFrame()->GetEventHandler().ShowNonLocatedContextMenu(element);
+ document->GetFrame()->GetEventHandler().ShowNonLocatedContextMenu(
+ element, kMenuSourceKeyboard);
return true;
}
@@ -3961,7 +4203,6 @@ bool AXObject::NameFromContents(bool recursive) const {
case ax::mojom::blink::Role::kLineBreak:
case ax::mojom::blink::Role::kLink:
case ax::mojom::blink::Role::kListBoxOption:
- case ax::mojom::blink::Role::kMenuButton:
case ax::mojom::blink::Role::kMenuItem:
case ax::mojom::blink::Role::kMenuItemCheckBox:
case ax::mojom::blink::Role::kMenuItemRadio:
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 1af1177bb55..270c0ee7896 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -8,14 +8,12 @@
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- * 2.
- * Redistributiothird_party/blink/renderer/modules/exported/web_ax_object.ccns
- * 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.
+ * 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
@@ -33,8 +31,10 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_OBJECT_H_
#include <ostream>
+#include <utility>
#include "base/macros.h"
+#include "base/optional.h"
#include "third_party/blink/public/web/web_ax_enums.h"
#include "third_party/blink/renderer/core/accessibility/axid.h"
#include "third_party/blink/renderer/core/dom/element.h"
@@ -52,6 +52,7 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "ui/accessibility/ax_enums.mojom-blink.h"
+#include "ui/accessibility/ax_mode.h"
class SkMatrix44;
@@ -82,8 +83,6 @@ enum class AOMRelationListProperty;
class AXSparseAttributeClient {
public:
virtual void AddBoolAttribute(AXBoolAttribute, bool) = 0;
- virtual void AddIntAttribute(AXIntAttribute, int32_t) = 0;
- virtual void AddUIntAttribute(AXUIntAttribute, uint32_t) = 0;
virtual void AddStringAttribute(AXStringAttribute, const String&) = 0;
virtual void AddObjectAttribute(AXObjectAttribute, AXObject&) = 0;
virtual void AddObjectVectorAttribute(AXObjectVectorAttribute,
@@ -404,7 +403,7 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
//
// TODO(crbug.com/1068668): AX onion soup - finish migrating
// BlinkAXTreeSource::SerializeNode into AXObject::Serialize.
- void Serialize(ui::AXNodeData* node_data);
+ void Serialize(ui::AXNodeData* node_data, ui::AXMode accessibility_mode);
// Determine subclass type.
virtual bool IsImageMapLink() const;
@@ -444,7 +443,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
bool IsLink() const;
virtual bool IsInPageLinkTarget() const;
bool IsMenu() const;
- bool IsMenuButton() const;
bool IsMenuRelated() const;
bool IsMeter() const;
virtual bool IsNativeImage() const;
@@ -527,7 +525,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
return true;
}
bool AccessibilityIsIgnoredByDefault(IgnoredReasons* = nullptr) const;
- AXObjectInclusion AccessibilityPlatformIncludesObject() const;
virtual AXObjectInclusion DefaultObjectInclusion(
IgnoredReasons* = nullptr) const;
bool IsInertOrAriaHidden() const;
@@ -538,10 +535,15 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
AXObject* LeafNodeAncestor() const;
bool IsDescendantOfDisabledNode() const;
bool ComputeAccessibilityIsIgnoredButIncludedInTree() const;
+ const AXObject* GetNativeTextControlAncestor(
+ int max_levels_to_check = 3) const;
const AXObject* DatetimeAncestor(int max_levels_to_check = 3) const;
const AXObject* DisabledAncestor() const;
bool LastKnownIsIgnoredValue() const;
+ void SetLastKnownIsIgnoredValue(bool);
bool LastKnownIsIgnoredButIncludedInTreeValue() const;
+ bool LastKnownIsIncludedInTreeValue() const;
+ void SetLastKnownIsIgnoredButIncludedInTreeValue(bool);
bool HasInheritedPresentationalRole() const;
bool IsPresentationalChild() const;
bool CanBeActiveDescendant() const;
@@ -659,10 +661,10 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual ax::mojom::blink::WritingDirection GetTextDirection() const {
return ax::mojom::blink::WritingDirection::kLtr;
}
+ virtual float GetTextIndent() const { return 0.0f; }
virtual ax::mojom::blink::TextPosition GetTextPosition() const {
return ax::mojom::blink::TextPosition::kNone;
}
- virtual int TextLength() const { return 0; }
virtual void GetTextStyleAndTextDecorationStyle(
int32_t* text_style,
@@ -683,29 +685,77 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// Load inline text boxes for just this node, even if
// settings->inlineTextBoxAccessibilityEnabled() is false.
- virtual void LoadInlineTextBoxes() {}
-
- // Walk the AXObjects on the same line. This is supported on any
- // object type but primarily intended to be used for inline text boxes.
- virtual AXObject* NextOnLine() const { return nullptr; }
- virtual AXObject* PreviousOnLine() const { return nullptr; }
-
- // For all node objects. The start and end character offset of each
- // marker, such as spelling or grammar error.
- virtual void Markers(Vector<DocumentMarker::MarkerType>&,
- Vector<AXRange>&) const;
- // For an inline text box.
- // The integer horizontal pixel offset of each character in the string;
- // negative values for RTL.
+ virtual void LoadInlineTextBoxes();
+
+ // Walk the AXObjects on the same line.
+ virtual AXObject* NextOnLine() const;
+ virtual AXObject* PreviousOnLine() const;
+
+ // Searches the object's ancestors for an aria-invalid attribute of type
+ // spelling or grammar, and returns a document marker representing the value
+ // of this attribute. As an optimization, goes up until the deepest line
+ // breaking object which, in most cases, is the paragraph containing this
+ // object.
+ base::Optional<const DocumentMarker::MarkerType>
+ GetAriaSpellingOrGrammarMarker() const;
+
+ // For all node and inline text box objects. The start and end character
+ // offset of each document marker, such as spelling or grammar error expressed
+ // as an AXRange.
+ virtual void GetDocumentMarkers(
+ Vector<DocumentMarker::MarkerType>* marker_types,
+ Vector<AXRange>* marker_ranges) const;
+
+ // For all inline text objects: Returns the horizontal pixel offset of each
+ // character in the object's text, rounded to the nearest integer. Negative
+ // values are returned for RTL text.
virtual void TextCharacterOffsets(Vector<int>&) const;
- // The start and end character offset of each word in the object's text.
+
+ // For all inline text boxes: Returns the start and end character offset of
+ // each word in the object's text.
virtual void GetWordBoundaries(Vector<int>& word_starts,
Vector<int>& word_ends) const;
- // Returns the text offset (text offset as in AXPosition, not as in
- // pixel offset) in the container of an inline text box.
- virtual unsigned TextOffsetInContainer(unsigned offset) const {
- return offset;
- }
+
+ virtual int TextLength() const { return 0; }
+
+ // Supported on layout inline, layout text, layout replaced, and layout block
+ // flow, provided that they are at inline-level, i.e. "display=inline" or
+ // "display=inline-block". Also supported on native text fields. For all other
+ // object types, returns |offset|.
+ //
+ // For layout inline, text, replaced, and block flow: Translates the given
+ // character offset to the equivalent offset in the object's formatting
+ // context. The formatting context is the deepest block flow ancestor,
+ // (excluding the current object), e.g. the containing paragraph. If this
+ // object is somehow not a descendant of a block flow in the layout tree,
+ // returns |offset|.
+ //
+ // For example, if this object is a span, and |offset| is 0, this method would
+ // return the number of characters, excluding any collapsed white space found
+ // in the DOM, from the start of the layout inline's deepest block flow
+ // ancestor, e.g. the beginning of the paragraph in which the span is found.
+ //
+ // For native text fields: Simply returns |offset|, because native text fields
+ // have no collapsed white space and so no translation from a DOM to an
+ // accessible text offset is necessary.
+ virtual int TextOffsetInFormattingContext(int offset) const;
+
+ // For all inline text boxes and native text fields. For all other object
+ // types, returns |offset|.
+ //
+ // For inline text boxes: Translates the given character offset to the
+ // equivalent offset in the object's static text or line break parent. If this
+ // object is somehow not a descendant of a block flow in the layout tree,
+ // returns the given offset.
+ //
+ // For example, if the given offset is 0, this would return the number of
+ // characters, excluding any collapsed white space found in the DOM, from the
+ // start of the inline text box's static text parent.
+ //
+ // For native text fields: Simply returns |offset|, because native text fields
+ // have no collapsed white space and so no translation from a DOM to an
+ // accessible text offset is necessary.
+ virtual int TextOffsetInContainer(int offset) const;
// Properties of interactive elements.
ax::mojom::blink::DefaultActionVerb Action() const;
@@ -856,6 +906,9 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// accessibility tree.
const AXObjectVector& ChildrenIncludingIgnored() const;
const AXObjectVector& ChildrenIncludingIgnored();
+ const AXObjectVector& CachedChildrenIncludingIgnored() const {
+ return children_;
+ }
// Returns the node's unignored descendants that are one level deeper than
// this node, after removing all accessibility ignored nodes from the tree.
@@ -1150,7 +1203,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
virtual void HandleAutofillStateChanged(WebAXAutofillState) {}
virtual void HandleAriaExpandedChanged() {}
virtual void SelectionChanged();
- virtual void TextChanged() {}
// Static helper functions.
static bool IsARIAControl(ax::mojom::blink::Role);
@@ -1175,6 +1227,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// Blink-internal DOM Node ID. Currently used for PDF exporting.
int GetDOMNodeId() const;
+ bool IsHiddenForTextAlternativeCalculation() const;
+
// Returns a string representation of this object.
String ToString(bool verbose = false) const;
@@ -1184,6 +1238,8 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
mutable bool have_children_;
ax::mojom::blink::Role role_;
ax::mojom::blink::Role aria_role_;
+ mutable AXObjectInclusion last_known_is_ignored_value_;
+ mutable AXObjectInclusion last_known_is_ignored_but_included_in_tree_value_;
LayoutRect explicit_element_rect_;
AXID explicit_container_id_;
@@ -1196,7 +1252,6 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
bool in_aria_labelled_by_traversal,
AXObjectSet& visited,
ax::mojom::blink::NameFrom& name_from);
- bool IsHiddenForTextAlternativeCalculation() const;
String AriaTextAlternative(bool recursive,
bool in_aria_labelled_by_traversal,
AXObjectSet& visited,
@@ -1271,6 +1326,11 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// functions called here may only search up the tree (ancestors), not down.
void UpdateCachedAttributeValuesIfNeeded() const;
+ // Helpers for serialization.
+ // TODO(meredithl): Serialize all sparse/table attributes and rename.
+ void SerializePartialSparseAttributes(ui::AXNodeData* node_data);
+ void SerializeTableAttributes(ui::AXNodeData* node_data);
+
private:
void UpdateDistributionForFlatTreeTraversal() const;
bool IsARIAControlledByTextboxWithActiveDescendant() const;
@@ -1300,6 +1360,14 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// not possible.
LayoutObject* GetLayoutObjectForNativeScrollAction() const;
+ // Max length for attributes such as aria-label.
+ static const uint32_t kMaxStringAttributeLength = 10000;
+ void TruncateAndAddStringAttribute(
+ ui::AXNodeData* dst,
+ ax::mojom::blink::StringAttribute attribute,
+ const std::string& value,
+ uint32_t max_len = kMaxStringAttributeLength) const;
+
static unsigned number_of_live_ax_objects_;
DISALLOW_COPY_AND_ASSIGN(AXObject);
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 e7001632e51..2e3fa955ea4 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
@@ -64,7 +64,6 @@
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/layout_progress.h"
-#include "third_party/blink/renderer/core/layout/layout_slider.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_table_row.h"
@@ -148,8 +147,11 @@ AXObjectCacheImpl::AXObjectCacheImpl(Document& document)
if (document_->LoadEventFinished())
AddPermissionStatusListener();
documents_.insert(&document);
- relation_cache_->Init();
use_ax_menu_list_ = GetSettings()->GetUseAXMenuList();
+
+ // Perform last, to ensure AXObjectCacheImpl() is fully set up, as
+ // AXRelationCache() sometimes calls back into AXObjectCacheImpl.
+ relation_cache_->Init();
}
AXObjectCacheImpl::~AXObjectCacheImpl() {
@@ -217,6 +219,20 @@ AXObject* AXObjectCacheImpl::GetOrCreateFocusedObjectFromNode(Node* node) {
if (auto* area = DynamicTo<HTMLAreaElement>(node))
return FocusedImageMapUIElement(area);
+ if (node->GetDocument() != GetDocument() &&
+ node->GetDocument().Lifecycle().GetState() <
+ DocumentLifecycle::kLayoutClean) {
+ // Node is in a different, unclean document. This can occur in an open
+ // popup. Ensure the popup document has a clean layout before trying to
+ // create an AXObject from a node in it.
+ if (node->GetDocument().View()) {
+ node->GetDocument()
+ .View()
+ ->UpdateLifecycleToCompositingCleanPlusScrolling(
+ DocumentUpdateReason::kAccessibility);
+ }
+ }
+
AXObject* obj = GetOrCreate(node);
if (!obj)
return nullptr;
@@ -304,6 +320,7 @@ static bool IsMenuListOption(const Node* node) {
return select->GetLayoutObject();
}
+// TODO(aleventhal) Remove side effects or rename, e.g. GetUpdated().
AXObject* AXObjectCacheImpl::Get(const Node* node) {
if (!node)
return nullptr;
@@ -333,6 +350,8 @@ AXObject* AXObjectCacheImpl::Get(const Node* node) {
if (layout_object && node_id && !layout_id && !IsMenuListOption(node) &&
!IsA<HTMLAreaElement>(node)) {
+ // Has a layout object but no layout_id, meaning that when the AXObject was
+ // originally created only for Node*, the LayoutObject* didn't exist yet.
// This can happen if an AXNodeObject is created for a node that's not laid
// out, but later something changes and it gets a layoutObject (like if it's
// reparented). It's also possible the layout object changed.
@@ -353,6 +372,9 @@ AXObject* AXObjectCacheImpl::Get(const Node* node) {
new_obj->SetAXObjectID(node_id);
objects_.Set(node_id, new_obj);
new_obj->Init();
+ new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
+ new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue(
+ new_obj->AccessibilityIsIgnoredButIncludedInTree());
return new_obj;
}
@@ -434,10 +456,13 @@ AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
if (IsA<HTMLOptionElement>(node))
return MakeGarbageCollected<AXListBoxOption>(layout_object, *this);
- auto* html_input_element = DynamicTo<HTMLInputElement>(node);
- if (html_input_element &&
- html_input_element->type() == input_type_names::kRadio)
- return MakeGarbageCollected<AXRadioInput>(layout_object, *this);
+ if (auto* html_input_element = DynamicTo<HTMLInputElement>(node)) {
+ const AtomicString& type = html_input_element->type();
+ if (type == input_type_names::kRadio)
+ return MakeGarbageCollected<AXRadioInput>(layout_object, *this);
+ if (type == input_type_names::kRange)
+ return MakeGarbageCollected<AXSlider>(layout_object, *this);
+ }
if (layout_object->IsSVGRoot())
return MakeGarbageCollected<AXSVGRoot>(layout_object, *this);
@@ -458,10 +483,6 @@ AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
return MakeGarbageCollected<AXProgressIndicator>(
ToLayoutProgress(css_box), *this);
}
-
- // input type=range
- if (auto* slider = DynamicTo<LayoutSlider>(css_box))
- return MakeGarbageCollected<AXSlider>(slider, *this);
}
return MakeGarbageCollected<AXLayoutObject>(layout_object, *this);
@@ -511,6 +532,14 @@ AXObject* AXObjectCacheImpl::GetOrCreate(Node* node) {
if (AXObject* obj = Get(node))
return obj;
+#if DCHECK_IS_ON()
+ Document* document = &node->GetDocument();
+ DCHECK(document);
+ DCHECK(document->Lifecycle().GetState() >=
+ DocumentLifecycle::kAfterPerformLayout)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
// If the node has a layout object, prefer using that as the primary key for
// the AXObject, with the exception of the HTMLAreaElement and nodes within
// a locked subtree, which are created based on its node.
@@ -534,6 +563,9 @@ AXObject* AXObjectCacheImpl::GetOrCreate(Node* node) {
DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
node_object_mapping_.Set(node, ax_id);
new_obj->Init();
+ new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
+ new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue(
+ new_obj->AccessibilityIsIgnoredButIncludedInTree());
MaybeNewRelationTarget(node, new_obj);
return new_obj;
@@ -546,6 +578,14 @@ AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) {
if (AXObject* obj = Get(layout_object))
return obj;
+#if DCHECK_IS_ON()
+ Document* document = &layout_object->GetDocument();
+ DCHECK(document);
+ DCHECK(document->Lifecycle().GetState() >=
+ DocumentLifecycle::kAfterPerformLayout)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
// Area elements are never created based on layout objects (see |Get|), so we
// really should never get here.
Node* node = layout_object->GetNode();
@@ -583,6 +623,9 @@ AXObject* AXObjectCacheImpl::GetOrCreate(LayoutObject* layout_object) {
layout_object_mapping_.Set(layout_object, axid);
new_obj->Init();
+ new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
+ new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue(
+ new_obj->AccessibilityIsIgnoredButIncludedInTree());
if (node && node->GetLayoutObject() == layout_object) {
AXID prev_axid = node_object_mapping_.at(node);
if (prev_axid != 0 && prev_axid != axid) {
@@ -612,18 +655,20 @@ AXObject* AXObjectCacheImpl::GetOrCreate(
inline_text_box_object_mapping_.Set(inline_text_box, axid);
new_obj->Init();
+ new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
+ new_obj->SetLastKnownIsIgnoredButIncludedInTreeValue(
+ new_obj->AccessibilityIsIgnoredButIncludedInTree());
return new_obj;
}
-AXObject* AXObjectCacheImpl::Create(ax::mojom::blink::Role role,
- AXObject* parent) {
+AXObject* AXObjectCacheImpl::GetOrCreate(ax::mojom::blink::Role role) {
AXObject* obj = nullptr;
switch (role) {
- case ax::mojom::blink::Role::kSliderThumb:
+ case ax::mojom::Role::kSliderThumb:
obj = MakeGarbageCollected<AXSliderThumb>(*this);
break;
- case ax::mojom::blink::Role::kMenuListPopup:
+ case ax::mojom::Role::kMenuListPopup:
DCHECK(use_ax_menu_list_);
obj = MakeGarbageCollected<AXMenuListPopup>(*this);
break;
@@ -635,7 +680,6 @@ AXObject* AXObjectCacheImpl::Create(ax::mojom::blink::Role role,
return nullptr;
GetOrCreateAXID(obj);
- obj->SetParent(parent);
obj->Init();
return obj;
@@ -754,6 +798,12 @@ AXID AXObjectCacheImpl::GenerateAXID() const {
return obj_id;
}
+void AXObjectCacheImpl::AddToFixedOrStickyNodeList(const AXObject* object) {
+ DCHECK(object);
+ DCHECK(!object->IsDetached());
+ fixed_or_sticky_node_ids_.insert(object->AXObjectID());
+}
+
AXID AXObjectCacheImpl::GetOrCreateAXID(AXObject* obj) {
// check for already-assigned ID
const AXID existing_axid = obj->AXObjectID();
@@ -775,6 +825,8 @@ void AXObjectCacheImpl::RemoveAXID(AXObject* object) {
if (!object)
return;
+ fixed_or_sticky_node_ids_.clear();
+
if (active_aria_modal_dialog_ == object)
active_aria_modal_dialog_ = nullptr;
@@ -818,6 +870,11 @@ void AXObjectCacheImpl::UpdateNumTreeUpdatesQueuedBeforeLayoutHistogram() {
tree_update_callback_queue_.size());
}
+void AXObjectCacheImpl::InvalidateBoundingBoxForFixedOrStickyPosition() {
+ for (AXID id : fixed_or_sticky_node_ids_)
+ changed_bounds_ids_.insert(id);
+}
+
void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
AXObject* obj) {
// Called for updates that do not have a DOM node, e.g. a children or text
@@ -827,10 +884,13 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
if (!IsActive(GetDocument()) || tree_updates_paused_)
return;
- Document& tree_update_document = *obj->GetDocument();
+ if (obj->IsDetached())
+ return;
+
+ Document* tree_update_document = obj->GetDocument();
// Ensure the tree update document is in a good state.
- if (!IsActive(tree_update_document))
+ if (!tree_update_document || !IsActive(*tree_update_document))
return;
if (tree_update_callback_queue_.size() >= max_pending_updates_) {
@@ -841,10 +901,10 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
return;
}
- DCHECK(!tree_update_document.GetPage()->Animator().IsServicingAnimations() ||
- (tree_update_document.Lifecycle().GetState() <
+ DCHECK(!tree_update_document->GetPage()->Animator().IsServicingAnimations() ||
+ (tree_update_document->Lifecycle().GetState() <
DocumentLifecycle::kInAccessibility ||
- tree_update_document.Lifecycle().StateAllowsDetach()))
+ tree_update_document->Lifecycle().StateAllowsDetach()))
<< "DeferTreeUpdateInternal should only be outside of the lifecycle or "
"before the accessibility state.";
tree_update_callback_queue_.push_back(MakeGarbageCollected<TreeUpdateParams>(
@@ -857,7 +917,7 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
}
void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
- Node* node) {
+ const Node* node) {
DCHECK(node);
if (!IsActive(GetDocument()) || tree_updates_paused_)
@@ -892,6 +952,14 @@ void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback,
}
void AXObjectCacheImpl::DeferTreeUpdate(
+ void (AXObjectCacheImpl::*method)(const Node*),
+ const Node* node) {
+ base::OnceClosure callback =
+ WTF::Bind(method, WrapWeakPersistent(this), WrapWeakPersistent(node));
+ DeferTreeUpdateInternal(std::move(callback), node);
+}
+
+void AXObjectCacheImpl::DeferTreeUpdate(
void (AXObjectCacheImpl::*method)(Node*),
Node* node) {
base::OnceClosure callback =
@@ -899,6 +967,19 @@ void AXObjectCacheImpl::DeferTreeUpdate(
DeferTreeUpdateInternal(std::move(callback), node);
}
+// TODO(accessibility) PostNotification calls made when layout is unclean should
+// use this instead, in order to avoid potentially unsafe calls to Get(), which
+// can call CreateFromRenderer(). For an example, see CheckedStateChanged().
+void AXObjectCacheImpl::DeferTreeUpdate(
+ void (AXObjectCacheImpl::*method)(Node* node,
+ ax::mojom::blink::Event event),
+ Node* node,
+ ax::mojom::blink::Event event) {
+ base::OnceClosure callback = WTF::Bind(method, WrapWeakPersistent(this),
+ WrapWeakPersistent(node), event);
+ DeferTreeUpdateInternal(std::move(callback), node);
+}
+
void AXObjectCacheImpl::DeferTreeUpdate(
void (AXObjectCacheImpl::*method)(const QualifiedName&, Element* element),
const QualifiedName& attr_name,
@@ -954,13 +1035,24 @@ void AXObjectCacheImpl::UpdateReverseRelations(
}
void AXObjectCacheImpl::StyleChanged(const LayoutObject* layout_object) {
+ DCHECK(layout_object);
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(layout_object->GetDocument());
+ Node* node = GetClosestNodeForLayoutObject(layout_object);
+ if (node)
+ DeferTreeUpdate(&AXObjectCacheImpl::StyleChangedWithCleanLayout, node);
+}
+
+void AXObjectCacheImpl::StyleChangedWithCleanLayout(Node* node) {
+ DCHECK(node);
+ DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
+
// There is a ton of style change notifications coming from newly-opened
// calendar popups for pickers. Solving that problem is what inspired the
// approach below, which is likely true for all elements.
//
// If we don't know about an object, then its style did not change as far as
// we (and ATs) are concerned. For this reason, don't call GetOrCreate.
- AXObject* obj = Get(layout_object);
+ AXObject* obj = Get(node);
if (!obj)
return;
@@ -970,7 +1062,7 @@ void AXObjectCacheImpl::StyleChanged(const LayoutObject* layout_object) {
// supports selection changes, it can be the result of the selection changing
// as well as the container losing focus. We handle these notifications via
// their state changes, so no need to mark them dirty here.
- AXObject* parent = obj->ParentObjectUnignored();
+ AXObject* parent = obj->CachedParentObject();
if (parent && ui::IsContainerWithSelectableChildren(parent->RoleValue()))
return;
@@ -981,6 +1073,12 @@ void AXObjectCacheImpl::TextChanged(Node* node) {
if (!node)
return;
+ // A text changed event is redundant with children changed on the same node.
+ if (nodes_with_pending_children_changed_.find(node) !=
+ nodes_with_pending_children_changed_.end()) {
+ return;
+ }
+
DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout, node);
}
@@ -993,21 +1091,28 @@ void AXObjectCacheImpl::TextChanged(const LayoutObject* layout_object) {
// when it has a block sibling.
Node* node = GetClosestNodeForLayoutObject(layout_object);
if (node) {
+ // A text changed event is redundant with children changed on the same node.
+ if (nodes_with_pending_children_changed_.find(node) !=
+ nodes_with_pending_children_changed_.end()) {
+ return;
+ }
+
DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout, node);
return;
}
- if (layout_object->GetNode() || Get(layout_object)) {
- DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout,
- layout_object->GetNode(), Get(layout_object));
+ if (Get(layout_object)) {
+ DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout, nullptr,
+ Get(layout_object));
}
}
void AXObjectCacheImpl::TextChangedWithCleanLayout(
Node* optional_node_for_relation_update,
AXObject* obj) {
- if (!obj && !optional_node_for_relation_update)
+ if (obj ? obj->IsDetached() : !optional_node_for_relation_update)
return;
+
#if DCHECK_IS_ON()
Document* document = obj ? obj->GetDocument()
: &optional_node_for_relation_update->GetDocument();
@@ -1016,7 +1121,15 @@ void AXObjectCacheImpl::TextChangedWithCleanLayout(
#endif // DCHECK_IS_ON()
if (obj) {
- obj->TextChanged();
+ if (obj->RoleValue() == ax::mojom::blink::Role::kStaticText) {
+ Settings* settings = GetSettings();
+ if (settings && settings->GetInlineTextBoxAccessibilityEnabled()) {
+ // Update inline text box children.
+ ChildrenChangedWithCleanLayout(optional_node_for_relation_update, obj);
+ return;
+ }
+ }
+
PostNotification(obj, ax::mojom::Event::kTextChanged);
}
@@ -1053,15 +1166,35 @@ void AXObjectCacheImpl::FocusableChangedWithCleanLayout(Element* element) {
void AXObjectCacheImpl::DocumentTitleChanged() {
DocumentLifecycle::DisallowTransitionScope disallow(document_->Lifecycle());
- PostNotification(Root(), ax::mojom::Event::kDocumentTitleChanged);
+ AXObject* root = Get(document_);
+ if (root)
+ PostNotification(root, ax::mojom::blink::Event::kDocumentTitleChanged);
}
void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttached(Node* node) {
+ DCHECK(node);
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
+ DeferTreeUpdate(
+ &AXObjectCacheImpl::UpdateCacheAfterNodeIsAttachedWithCleanLayout, node);
+}
+
+void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttachedWithCleanLayout(
+ Node* node) {
+ if (!node || !node->isConnected())
+ return;
+
Element* element = DynamicTo<Element>(node);
if (!element)
return;
- SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
+ Document* document = &node->GetDocument();
+ if (!document)
+ return;
+
+#if DCHECK_IS_ON()
+ DCHECK(document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
// Process any relation attributes that can affect ax objects already created.
@@ -1070,7 +1203,7 @@ void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttached(Node* node) {
if (element->FastHasAttribute(html_names::kAriaOwnsAttr) ||
element->HasExplicitlySetAttrAssociatedElements(
html_names::kAriaOwnsAttr)) {
- HandleAttributeChanged(html_names::kAriaOwnsAttr, element);
+ HandleAttributeChangedWithCleanLayout(html_names::kAriaOwnsAttr, element);
}
MaybeNewRelationTarget(node, Get(node));
@@ -1080,13 +1213,24 @@ void AXObjectCacheImpl::DidInsertChildrenOfNode(Node* node) {
// If a node is inserted that is a descendant of a leaf node in the
// accessibility tree, notify the root of that subtree that its children have
// changed.
+ DCHECK(node);
+ DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, node);
+}
+
+void AXObjectCacheImpl::DidInsertChildrenOfNodeWithCleanLayout(Node* node) {
if (!node)
return;
+#if DCHECK_IS_ON()
+ Document* document = &node->GetDocument();
+ DCHECK(document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
if (AXObject* obj = Get(node)) {
- TextChanged(node);
+ TextChangedWithCleanLayout(node);
} else {
- DidInsertChildrenOfNode(NodeTraversal::Parent(*node));
+ DidInsertChildrenOfNodeWithCleanLayout(NodeTraversal::Parent(*node));
}
}
@@ -1105,6 +1249,7 @@ void AXObjectCacheImpl::ChildrenChanged(const LayoutObject* layout_object) {
if (!layout_object)
return;
+ // Update using nearest node (walking ancestors if necessary).
Node* node = GetClosestNodeForLayoutObject(layout_object);
if (node) {
@@ -1113,12 +1258,46 @@ void AXObjectCacheImpl::ChildrenChanged(const LayoutObject* layout_object) {
return;
DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, node);
+
+ if (layout_object->GetNode() == node)
+ return; // Node matched the layout object passed in, no further updates.
+
+ // Node was for an ancestor of an anonymous layout object passed in.
+ // layout object was anonymous. Fall through to continue updating
+ // descendants of the matching AXObject for the layout object.
+ }
+
+ // Update using layout object.
+ // Only using the layout object when no node could be found to update.
+ AXObject* ax_layout_obj = Get(layout_object);
+ if (!ax_layout_obj)
return;
+
+ if (ax_layout_obj->LastKnownIsIncludedInTreeValue()) {
+ // Participates in tree: update children if they haven't already been.
+ DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout,
+ ax_layout_obj->GetNode(), ax_layout_obj);
}
- if (AXObject* obj = Get(layout_object)) {
- DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, nullptr,
- obj);
+ // Invalidate child ax objects below an anonymous layout object.
+ // The passed-in layout object was anonymous, e.g. anonymous block flow
+ // inserted by blink as an inline's parent when it had a block sibling.
+ // If children change on an anonymous layout object, this can
+ // mean that child AXObjects actually had their children change.
+ // Therefore, invalidate any of those children as well, using the nearest
+ // parent that participates in the tree.
+ // In this example, if ChildrenChanged() is called on the anonymous block,
+ // then we also process ChildrenChanged() on the <div> and <a>:
+ // <div>
+ // | \
+ // <p> Anonymous block
+ // \
+ // <a>
+ // \
+ // text
+ for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node); child;
+ child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
+ DeferTreeUpdate(&AXObjectCacheImpl::ChildrenChangedWithCleanLayout, child);
}
}
@@ -1137,12 +1316,6 @@ void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* node) {
if (!node)
return;
-#ifndef NDEBUG
- if (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) {
- LOG(ERROR) << "Node needs layout tree update: " << node;
- node->ShowTreeForThisAcrossFrame();
- }
-#endif
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
ChildrenChangedWithCleanLayout(node, Get(node));
@@ -1150,7 +1323,7 @@ void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* node) {
void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* optional_node,
AXObject* obj) {
- if (!obj && !optional_node)
+ if (obj ? obj->IsDetached() : !optional_node)
return;
#if DCHECK_IS_ON()
@@ -1159,7 +1332,7 @@ void AXObjectCacheImpl::ChildrenChangedWithCleanLayout(Node* optional_node,
<< "Unclean document at lifecycle " << document->Lifecycle().ToString();
#endif // DCHECK_IS_ON()
- if (obj)
+ if (obj && !obj->IsDetached())
obj->ChildrenChanged();
if (optional_node) {
@@ -1181,6 +1354,11 @@ void AXObjectCacheImpl::ProcessDeferredAccessibilityEvents(Document& document) {
PostNotifications(document);
}
+bool AXObjectCacheImpl::IsDirty() const {
+ return !tree_updates_paused_ &&
+ (tree_update_callback_queue_.size() || notifications_to_post_.size());
+}
+
void AXObjectCacheImpl::EmbeddingTokenChanged(HTMLFrameOwnerElement* element) {
if (!element)
return;
@@ -1204,7 +1382,7 @@ void AXObjectCacheImpl::ProcessUpdates(Document& document) {
nodes_with_pending_children_changed_.clear();
for (auto& tree_update : old_tree_update_callback_queue) {
- Node* node = tree_update->node;
+ const Node* node = tree_update->node;
AXID axid = tree_update->axid;
// Need either an DOM node or an AXObject to be a valid update.
@@ -1265,6 +1443,8 @@ void AXObjectCacheImpl::PostNotification(const LayoutObject* layout_object,
PostNotification(Get(layout_object), notification);
}
+// TODO(accessibility) Eventually replace direct calls during unclean layout
+// with deferred calls.
void AXObjectCacheImpl::PostNotification(Node* node,
ax::mojom::blink::Event notification) {
if (!node)
@@ -1272,6 +1452,14 @@ void AXObjectCacheImpl::PostNotification(Node* node,
PostNotification(Get(node), notification);
}
+void AXObjectCacheImpl::EnsurePostNotification(
+ Node* node,
+ ax::mojom::blink::Event notification) {
+ if (!node)
+ return;
+ PostNotification(GetOrCreate(node), notification);
+}
+
void AXObjectCacheImpl::PostNotification(AXObject* object,
ax::mojom::blink::Event event_type) {
if (!object || !object->AXObjectID() || object->IsDetached())
@@ -1412,7 +1600,8 @@ bool AXObjectCacheImpl::MayHaveHTMLLabel(const HTMLElement& elem) {
}
void AXObjectCacheImpl::CheckedStateChanged(Node* node) {
- PostNotification(node, ax::mojom::Event::kCheckedStateChanged);
+ DeferTreeUpdate(&AXObjectCacheImpl::PostNotification, node,
+ ax::mojom::blink::Event::kCheckedStateChanged);
}
void AXObjectCacheImpl::ListboxOptionStateChanged(HTMLOptionElement* option) {
@@ -1524,20 +1713,35 @@ void AXObjectCacheImpl::HandleNodeLostFocusWithCleanLayout(Node* node) {
if (!obj)
return;
+ TRACE_EVENT1("accessibility",
+ "AXObjectCacheImpl::HandleNodeLostFocusWithCleanLayout", "id",
+ obj->AXObjectID());
PostNotification(obj, ax::mojom::Event::kBlur);
}
void AXObjectCacheImpl::HandleNodeGainedFocusWithCleanLayout(Node* node) {
- DCHECK(node);
- DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
- // Something about the call chain for this method seems to leave distribution
- // in a dirty state - update it before we call GetOrCreate so that we don't
- // crash.
+ node = FocusedElement(); // Needs to get this with clean layout.
+ if (!node || !node->GetDocument().View())
+ return;
node->UpdateDistributionForFlatTreeTraversal();
+
+ if (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) {
+ // This should only occur when focus goes into a popup document. The main
+ // document has an updated layout, but the popup does not.
+ // TODO(accessibility) design callback system so that popup processing
+ // can occur with a clean layout.
+ DCHECK_NE(document_, node->GetDocument());
+ node->GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(
+ DocumentUpdateReason::kAccessibility);
+ }
+
AXObject* obj = GetOrCreateFocusedObjectFromNode(node);
if (!obj)
return;
+ TRACE_EVENT1("accessibility",
+ "AXObjectCacheImpl::HandleNodeGainedFocusWithCleanLayout", "id",
+ obj->AXObjectID());
PostNotification(obj, ax::mojom::Event::kFocus);
}
@@ -1593,9 +1797,6 @@ void AXObjectCacheImpl::HandleRoleChangeWithCleanLayout(Node* node) {
// If role changes on a table, invalidate the entire table subtree as many
// objects may suddenly need to change, because presentation is inherited
// from the table to rows and cells.
- // TODO(aleventhal) A size change on a select means the children may need to
- // switch between AXMenuListOption and AXListBoxOption.
- // For some reason we don't get attribute changes for @size, though.
LayoutObject* layout_object = node->GetLayoutObject();
if (layout_object && layout_object->IsTable())
InvalidateTableSubtree(obj);
@@ -1628,10 +1829,9 @@ void AXObjectCacheImpl::HandleRoleChangeIfNotEditableWithCleanLayout(
// However, doing that would require
// waiting for layout to complete, as ComputeAccessibilityRole() looks at
// layout objects.
- if (AXObject* obj = Get(node)) {
- if (!obj->IsTextControl())
- HandleRoleChangeWithCleanLayout(node);
- }
+ AXObject* obj = Get(node);
+ if (!obj || !obj->IsTextControl())
+ HandleRoleChangeWithCleanLayout(node);
}
void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
@@ -1694,7 +1894,7 @@ void AXObjectCacheImpl::HandleAttributeChangedWithCleanLayout(
TextChangedWithCleanLayout(element);
} else if (attr_name == html_names::kAriaCheckedAttr ||
attr_name == html_names::kAriaPressedAttr) {
- CheckedStateChanged(element);
+ PostNotification(element, ax::mojom::blink::Event::kCheckedStateChanged);
} else if (attr_name == html_names::kAriaSelectedAttr) {
HandleAriaSelectedChangedWithCleanLayout(element);
} else if (attr_name == html_names::kAriaExpandedAttr) {
@@ -1788,7 +1988,25 @@ void AXObjectCacheImpl::RemoveValidationMessageObject() {
// Native validation error popup for focused form control in current document.
void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged(
- const Element* form_control) {
+ const Node* form_control) {
+ DCHECK(form_control);
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(form_control->GetDocument());
+
+ DeferTreeUpdate(&AXObjectCacheImpl::
+ HandleValidationMessageVisibilityChangedWithCleanLayout,
+ form_control);
+}
+
+void AXObjectCacheImpl::HandleValidationMessageVisibilityChangedWithCleanLayout(
+ const Node* form_control) {
+#if DCHECK_IS_ON()
+ DCHECK(form_control);
+ Document* document = &form_control->GetDocument();
+ DCHECK(document);
+ DCHECK(document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
AXObject* message_ax_object = ValidationMessageObjectIfInvalid();
if (message_ax_object)
MarkAXObjectDirty(message_ax_object, false); // May be invisible now.
@@ -1924,7 +2142,7 @@ void AXObjectCacheImpl::MarkAXObjectDirty(AXObject* obj, bool subtree) {
webframe->Client()->MarkWebAXObjectDirty(WebAXObject(obj), subtree);
}
-void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) {
+void AXObjectCacheImpl::MarkElementDirty(const Node* element, bool subtree) {
// Warning, if no AXObject exists for element, nothing is marked dirty,
// including descendant objects when subtree == true.
MarkAXObjectDirty(Get(element), subtree);
@@ -1933,6 +2151,8 @@ void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) {
void AXObjectCacheImpl::HandleFocusedUIElementChanged(
Element* old_focused_element,
Element* new_focused_element) {
+ TRACE_EVENT0("accessibility",
+ "AXObjectCacheImpl::HandleFocusedUIElementChanged");
#if DCHECK_IS_ON()
// The focus can be in a different document when a popup is open.
Document& focused_doc =
@@ -2094,26 +2314,38 @@ void AXObjectCacheImpl::HandleUpdateActiveMenuOption(LayoutObject* menu_list,
}
void AXObjectCacheImpl::DidShowMenuListPopup(LayoutObject* menu_list) {
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
+
+ DCHECK(menu_list->GetNode());
+ DeferTreeUpdate(&AXObjectCacheImpl::DidShowMenuListPopupWithCleanLayout,
+ menu_list->GetNode());
+}
+
+void AXObjectCacheImpl::DidShowMenuListPopupWithCleanLayout(Node* menu_list) {
if (!use_ax_menu_list_) {
MarkAXObjectDirty(Get(menu_list), false);
return;
}
- SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
-
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list));
if (ax_object)
ax_object->DidShowPopup();
}
void AXObjectCacheImpl::DidHideMenuListPopup(LayoutObject* menu_list) {
+ SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
+
+ DCHECK(menu_list->GetNode());
+ DeferTreeUpdate(&AXObjectCacheImpl::DidHideMenuListPopupWithCleanLayout,
+ menu_list->GetNode());
+}
+
+void AXObjectCacheImpl::DidHideMenuListPopupWithCleanLayout(Node* menu_list) {
if (!use_ax_menu_list_) {
MarkAXObjectDirty(Get(menu_list), false);
return;
}
- SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
-
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list));
if (ax_object)
ax_object->DidHidePopup();
@@ -2122,14 +2354,35 @@ void AXObjectCacheImpl::DidHideMenuListPopup(LayoutObject* menu_list) {
void AXObjectCacheImpl::HandleLoadComplete(Document* document) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*document);
- PostNotification(GetOrCreate(document), ax::mojom::Event::kLoadComplete);
AddPermissionStatusListener();
+ DeferTreeUpdate(&AXObjectCacheImpl::HandleLoadCompleteWithCleanLayout,
+ document);
+}
+
+void AXObjectCacheImpl::HandleLoadCompleteWithCleanLayout(Node* document_node) {
+ DCHECK(document_node);
+ DCHECK(IsA<Document>(document_node));
+#if DCHECK_IS_ON()
+ Document* document = To<Document>(document_node);
+ DCHECK(document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean)
+ << "Unclean document at lifecycle " << document->Lifecycle().ToString();
+#endif // DCHECK_IS_ON()
+
+ AddPermissionStatusListener();
+ PostNotification(GetOrCreate(document_node),
+ ax::mojom::blink::Event::kLoadComplete);
}
void AXObjectCacheImpl::HandleLayoutComplete(Document* document) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*document);
-
- PostNotification(GetOrCreate(document), ax::mojom::Event::kLayoutComplete);
+ if (document->Lifecycle().GetState() >=
+ DocumentLifecycle::kAfterPerformLayout) {
+ PostNotification(GetOrCreate(document),
+ ax::mojom::blink::Event::kLayoutComplete);
+ } else {
+ DeferTreeUpdate(&AXObjectCacheImpl::EnsurePostNotification, document,
+ ax::mojom::blink::Event::kLayoutComplete);
+ }
}
void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) {
@@ -2160,15 +2413,20 @@ void AXObjectCacheImpl::HandleScrollPositionChanged(
LocalFrameView* frame_view) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*frame_view->GetFrame().GetDocument());
- AXObject* target_ax_object = GetOrCreate(document_);
- PostNotification(target_ax_object, ax::mojom::Event::kScrollPositionChanged);
+ InvalidateBoundingBoxForFixedOrStickyPosition();
+ DeferTreeUpdate(&AXObjectCacheImpl::EnsurePostNotification, document_,
+ ax::mojom::blink::Event::kScrollPositionChanged);
}
void AXObjectCacheImpl::HandleScrollPositionChanged(
LayoutObject* layout_object) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(layout_object->GetDocument());
- PostNotification(GetOrCreate(layout_object),
- ax::mojom::Event::kScrollPositionChanged);
+ InvalidateBoundingBoxForFixedOrStickyPosition();
+ Node* node = GetClosestNodeForLayoutObject(layout_object);
+ if (node) {
+ DeferTreeUpdate(&AXObjectCacheImpl::EnsurePostNotification, node,
+ ax::mojom::blink::Event::kScrollPositionChanged);
+ }
}
const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* 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 0520c1692aa..8bd04ea5a87 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
@@ -124,7 +124,7 @@ class MODULES_EXPORT AXObjectCacheImpl
void HandleAttributeChanged(const QualifiedName& attr_name,
Element*) override;
void HandleValidationMessageVisibilityChanged(
- const Element* form_control) override;
+ const Node* form_control) override;
void HandleFocusedUIElementChanged(Element* old_focused_element,
Element* new_focused_element) override;
void HandleInitialFocus() override;
@@ -148,6 +148,7 @@ class MODULES_EXPORT AXObjectCacheImpl
void InlineTextBoxesUpdated(LineLayoutItem) override;
void ProcessDeferredAccessibilityEvents(Document&) override;
+ bool IsDirty() const override;
// Called when a HTMLFrameOwnerElement (such as an iframe element) changes the
// embedding token of its child frame.
@@ -175,9 +176,8 @@ class MODULES_EXPORT AXObjectCacheImpl
AXObject* ObjectFromAXID(AXID id) const { return objects_.at(id); }
AXObject* Root();
- // Used for objects without backing DOM nodes, layout objects, etc.
- AXObject* Create(ax::mojom::blink::Role, AXObject* parent);
-
+ // used for objects without backing elements
+ AXObject* GetOrCreate(ax::mojom::blink::Role);
AXObject* GetOrCreate(AccessibleNode*);
AXObject* GetOrCreate(LayoutObject*) override;
AXObject* GetOrCreate(const Node*);
@@ -209,6 +209,14 @@ class MODULES_EXPORT AXObjectCacheImpl
void HandleAriaSelectedChangedWithCleanLayout(Node*);
void HandleNodeLostFocusWithCleanLayout(Node*);
void HandleNodeGainedFocusWithCleanLayout(Node*);
+ void HandleLoadCompleteWithCleanLayout(Node*);
+ void UpdateCacheAfterNodeIsAttachedWithCleanLayout(Node*);
+ void DidShowMenuListPopupWithCleanLayout(Node*);
+ void DidHideMenuListPopupWithCleanLayout(Node*);
+ void StyleChangedWithCleanLayout(Node*);
+ void DidInsertChildrenOfNodeWithCleanLayout(Node*);
+ void HandleScrollPositionChangedWithCleanLayout(Node*);
+ void HandleValidationMessageVisibilityChangedWithCleanLayout(const Node*);
bool InlineTextBoxAccessibilityEnabled();
@@ -221,10 +229,14 @@ class MODULES_EXPORT AXObjectCacheImpl
int ModificationCount() const { return modification_count_; }
void PostNotification(const LayoutObject*, ax::mojom::blink::Event);
- void PostNotification(Node*, ax::mojom::Event);
+ // Creates object if necessary.
+ void EnsurePostNotification(Node*, ax::mojom::blink::Event);
+ // Does not create object.
+ // TODO(accessibility) Find out if we can merge with EnsurePostNotification().
+ void PostNotification(Node*, ax::mojom::blink::Event);
void PostNotification(AXObject*, ax::mojom::blink::Event);
void MarkAXObjectDirty(AXObject*, bool subtree);
- void MarkElementDirty(const Element*, bool subtree);
+ void MarkElementDirty(const Node*, bool subtree);
//
// Aria-owns support.
@@ -260,6 +272,10 @@ class MODULES_EXPORT AXObjectCacheImpl
const HeapVector<Member<Element>>& attr_associated_elements,
HeapVector<Member<AXObject>>& owned_children);
+ // Adds |object| to |fixed_or_sticky_node_ids_| if it has a fixed or sticky
+ // position.
+ void AddToFixedOrStickyNodeList(const AXObject* object);
+
bool MayHaveHTMLLabel(const HTMLElement& elem);
// Synchronously returns whether or not we currently have permission to
@@ -332,7 +348,7 @@ class MODULES_EXPORT AXObjectCacheImpl
};
struct TreeUpdateParams final : public GarbageCollected<TreeUpdateParams> {
- TreeUpdateParams(Node* node,
+ TreeUpdateParams(const Node* node,
AXID axid,
ax::mojom::blink::EventFrom event_from,
const BlinkAXEventIntentsSet& intents,
@@ -345,7 +361,7 @@ class MODULES_EXPORT AXObjectCacheImpl
event_intents.insert(intent.key, intent.value);
}
}
- WeakMember<Node> node;
+ WeakMember<const Node> node;
AXID axid;
ax::mojom::blink::EventFrom event_from;
BlinkAXEventIntentsSet event_intents;
@@ -428,7 +444,14 @@ class MODULES_EXPORT AXObjectCacheImpl
// Enqueue a callback to the given method to be run after layout is
// complete.
+ void DeferTreeUpdate(void (AXObjectCacheImpl::*method)(const Node*),
+ const Node* node);
void DeferTreeUpdate(void (AXObjectCacheImpl::*method)(Node*), Node* node);
+ void DeferTreeUpdate(
+ void (AXObjectCacheImpl::*method)(Node* node,
+ ax::mojom::blink::Event event),
+ Node* node,
+ ax::mojom::blink::Event event);
void DeferTreeUpdate(void (AXObjectCacheImpl::*method)(const QualifiedName&,
Element* element),
const QualifiedName& attr_name,
@@ -439,8 +462,7 @@ class MODULES_EXPORT AXObjectCacheImpl
Node* node,
AXObject* obj);
- void DeferTreeUpdateInternal(base::OnceClosure callback, Node* node);
-
+ void DeferTreeUpdateInternal(base::OnceClosure callback, const Node* node);
void DeferTreeUpdateInternal(base::OnceClosure callback, AXObject* obj);
void SelectionChangedWithCleanLayout(Node* node);
@@ -479,6 +501,12 @@ class MODULES_EXPORT AXObjectCacheImpl
void UpdateNumTreeUpdatesQueuedBeforeLayoutHistogram();
+ // Invalidates the bounding boxes of fixed or sticky positioned objects which
+ // should be updated when the scroll offset is changed. Like
+ // InvalidateBoundingBox, it can be later retrieved by
+ // GetAllObjectsWithChangedBounds.
+ void InvalidateBoundingBoxForFixedOrStickyPosition();
+
// Whether the user has granted permission for the user to install event
// listeners for accessibility events using the AOM.
mojom::PermissionStatus accessibility_event_permission_;
@@ -509,6 +537,9 @@ class MODULES_EXPORT AXObjectCacheImpl
// GetAllObjectsWithChangedBounds was called.
HashSet<AXID> changed_bounds_ids_;
+ // The list of node IDs whose position is fixed or sticky.
+ HashSet<AXID> fixed_or_sticky_node_ids_;
+
// The source of the event that is currently being handled.
ax::mojom::blink::EventFrom active_event_from_ =
ax::mojom::blink::EventFrom::kNone;
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
index fdb60f4a4b7..07c15dc79f6 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
@@ -517,6 +517,71 @@ TEST_F(AccessibilityTest, AxNodeObjectContainsInPageLinkTarget) {
EXPECT_EQ(anchor->Url(), KURL("http://test.com/#target"));
}
+TEST_F(AccessibilityTest, AxNodeObjectInPageLinkTargetNonAscii) {
+ GetDocument().SetURL(KURL("http://test.com"));
+ // ö is U+00F6 which URI encodes to %C3%B6
+ //
+ // This file is forced to be UTF-8 by the build system,
+ // the uR"" will create char16_t[] of UTF-16,
+ // WTF::String will wrap the char16_t* as UTF-16.
+ // All this is checked by ensuring a match against u"\u00F6".
+ //
+ // TODO(1117212): The escaped version currently takes precedence.
+ // <h1 id="%C3%B6">O2</h1>
+ SetBodyInnerHTML(
+ uR"HTML(
+ <a href="#ö" id="anchor">O</a>
+ <h1 id="ö">O</h1>"
+ <a href="#t%6Fp" id="top_test">top</a>"
+ <a href="#" id="empty_test">also top</a>");
+ )HTML");
+
+ {
+ // anchor
+ const AXObject* anchor = GetAXObjectByElementId("anchor");
+ ASSERT_NE(nullptr, anchor);
+
+ EXPECT_FALSE(anchor->Url().IsEmpty());
+ EXPECT_EQ(anchor->Url(), KURL(u"http://test.com/#\u00F6"));
+
+ const AXObject* target = anchor->InPageLinkTarget();
+ ASSERT_NE(nullptr, target);
+
+ auto* targetElement = DynamicTo<Element>(target->GetNode());
+ ASSERT_NE(nullptr, target);
+ ASSERT_TRUE(targetElement->HasID());
+ EXPECT_EQ(targetElement->IdForStyleResolution(), String(u"\u00F6"));
+ }
+
+ {
+ // top_test
+ const AXObject* anchor = GetAXObjectByElementId("top_test");
+ ASSERT_NE(nullptr, anchor);
+
+ EXPECT_FALSE(anchor->Url().IsEmpty());
+ EXPECT_EQ(anchor->Url(), KURL(u"http://test.com/#t%6Fp"));
+
+ const AXObject* target = anchor->InPageLinkTarget();
+ ASSERT_NE(nullptr, target);
+
+ EXPECT_EQ(&GetDocument(), target->GetNode());
+ }
+
+ {
+ // empty_test
+ const AXObject* anchor = GetAXObjectByElementId("empty_test");
+ ASSERT_NE(nullptr, anchor);
+
+ EXPECT_FALSE(anchor->Url().IsEmpty());
+ EXPECT_EQ(anchor->Url(), KURL(u"http://test.com/#"));
+
+ const AXObject* target = anchor->InPageLinkTarget();
+ ASSERT_NE(nullptr, target);
+
+ EXPECT_EQ(&GetDocument(), target->GetNode());
+ }
+}
+
TEST_P(ParameterizedAccessibilityTest, NextOnLine) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -614,21 +679,17 @@ TEST_F(AccessibilityTest, CheckNoDuplicateChildren) {
ax_select->FirstChildIncludingIgnored()->ChildCountIncludingIgnored(), 1);
}
-TEST_F(AccessibilityTest, InitRelationCache) {
- // All of the other tests already have accessibility initialized
+TEST_F(AccessibilityTest, InitRelationCacheLabelFor) {
+ // Most other tests already have accessibility initialized
// first, but we don't want to in this test.
//
// Get rid of the AXContext so the AXObjectCache is destroyed.
ax_context_.reset(nullptr);
SetBodyInnerHTML(R"HTML(
- <ul id="ul" aria-owns="li"></ul>
<label for="a"></label>
<input id="a">
<input id="b">
- <div role="section" id="div">
- <li id="li"></li>
- </div>
)HTML");
// Now recreate an AXContext, simulating what happens if accessibility
@@ -641,11 +702,28 @@ TEST_F(AccessibilityTest, InitRelationCache) {
ASSERT_NE(nullptr, input_a);
const AXObject* input_b = GetAXObjectByElementId("b");
ASSERT_NE(nullptr, input_b);
+}
+
+TEST_F(AccessibilityTest, InitRelationCacheAriaOwns) {
+ // Most other tests already have accessibility initialized
+ // first, but we don't want to in this test.
+ //
+ // Get rid of the AXContext so the AXObjectCache is destroyed.
+ ax_context_.reset(nullptr);
+
+ SetBodyInnerHTML(R"HTML(
+ <ul id="ul" aria-owns="li"></ul>
+ <div role="section" id="div">
+ <li id="li"></li>
+ </div>
+ )HTML");
- EXPECT_TRUE(GetAXObjectCache().MayHaveHTMLLabel(
- To<HTMLElement>(*input_a->GetNode())));
- EXPECT_FALSE(GetAXObjectCache().MayHaveHTMLLabel(
- To<HTMLElement>(*input_b->GetNode())));
+ // Now recreate an AXContext, simulating what happens if accessibility
+ // is enabled after the document is loaded.
+ ax_context_.reset(new AXContext(GetDocument()));
+
+ const AXObject* root = GetAXRootObject();
+ ASSERT_NE(nullptr, root);
// Note: retrieve the LI first and check that its parent is not
// the paragraph element. If we were to retrieve the UL element,
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 164c7b48204..90dbe5c0989 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.cc
@@ -9,12 +9,10 @@
#include "third_party/blink/renderer/core/dom/document.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/editing/ephemeral_range.h"
-#include "third_party/blink/renderer/core/editing/iterators/character_iterator.h"
-#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
-#include "third_party/blink/renderer/core/editing/iterators/text_iterator_behavior.h"
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.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/modules/accessibility/ax_layout_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
@@ -240,15 +238,40 @@ const AXPosition AXPosition::FromPosition(
AXPosition ax_position(*container);
// Convert from a DOM offset that may have uncompressed white space to a
// character offset.
- // TODO(nektar): Use LayoutNG offset mapping instead of
- // |TextIterator|.
- TextIteratorBehavior::Builder iterator_builder;
- const TextIteratorBehavior text_iterator_behavior =
- iterator_builder.SetDoesNotEmitSpaceBeyondRangeEnd(true).Build();
- const auto first_position = Position::FirstPositionInNode(*container_node);
- int offset = TextIterator::RangeLength(
- first_position, parent_anchored_position, text_iterator_behavior);
- ax_position.text_offset_or_child_index_ = offset;
+ //
+ // Note that NGOffsetMapping::GetInlineFormattingContextOf will reject DOM
+ // positions that it does not support, so we don't need to explicitly check
+ // this before calling the method.)
+ LayoutBlockFlow* formatting_context =
+ NGOffsetMapping::GetInlineFormattingContextOf(parent_anchored_position);
+ const NGOffsetMapping* container_offset_mapping =
+ formatting_context ? NGInlineNode::GetOffsetMapping(formatting_context)
+ : nullptr;
+ if (!container_offset_mapping) {
+ // We are unable to compute the text offset in the accessibility tree that
+ // corresponds to the DOM offset. We do the next best thing by returning
+ // either the first or the last AX position in |container| based on the
+ // |adjustment_behavior|.
+ switch (adjustment_behavior) {
+ case AXPositionAdjustmentBehavior::kMoveRight:
+ return CreateLastPositionInObject(*container, adjustment_behavior);
+ case AXPositionAdjustmentBehavior::kMoveLeft:
+ return CreateFirstPositionInObject(*container, adjustment_behavior);
+ }
+ }
+
+ // We can now compute the text offset that corresponds to the given DOM
+ // position from the beginning of our formatting context. We also need to
+ // subtract the text offset of our |container| from the beginning of the
+ // same formatting context.
+ int container_offset = container->TextOffsetInFormattingContext(0);
+ int text_offset =
+ int{container_offset_mapping
+ ->GetTextContentOffset(parent_anchored_position)
+ .value_or(static_cast<unsigned int>(container_offset))} -
+ container_offset;
+ DCHECK_GE(text_offset, 0);
+ ax_position.text_offset_or_child_index_ = text_offset;
ax_position.affinity_ = affinity;
#if DCHECK_IS_ON()
String failure_reason;
@@ -392,10 +415,13 @@ int AXPosition::MaxTextOffset() const {
return 0;
}
+ // TODO(nektar): Make AXObject::TextLength() public and use throughout this
+ // method.
if (container_object_->IsNativeTextControl())
return container_object_->StringValue().length();
- if (container_object_->IsAXInlineTextBox() || !container_object_->GetNode()) {
+ const Node* container_node = container_object_->GetNode();
+ if (container_object_->IsAXInlineTextBox() || !container_node) {
// 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
// only part of it.
@@ -405,16 +431,29 @@ int AXPosition::MaxTextOffset() const {
return container_object_->ComputedName().length();
}
- // TODO(nektar): Use LayoutNG offset mapping instead of |TextIterator|.
- TextIteratorBehavior::Builder iterator_builder;
- const TextIteratorBehavior text_iterator_behavior =
- iterator_builder.SetDoesNotEmitSpaceBeyondRangeEnd(true).Build();
- const auto first_position =
- Position::FirstPositionInNode(*container_object_->GetNode());
- const auto last_position =
- Position::LastPositionInNode(*container_object_->GetNode());
- return TextIterator::RangeLength(first_position, last_position,
- text_iterator_behavior);
+ const LayoutObject* layout_object = container_node->GetLayoutObject();
+ if (!layout_object)
+ return container_object_->ComputedName().length();
+ // TODO(nektar): Remove all this logic once we switch to
+ // AXObject::TextLength().
+ const bool is_atomic_inline_level =
+ layout_object->IsInline() && layout_object->IsAtomicInlineLevel();
+ if (!is_atomic_inline_level && !layout_object->IsText())
+ return container_object_->ComputedName().length();
+
+ LayoutBlockFlow* formatting_context =
+ NGOffsetMapping::GetInlineFormattingContextOf(*layout_object);
+ const NGOffsetMapping* container_offset_mapping =
+ formatting_context ? NGInlineNode::GetOffsetMapping(formatting_context)
+ : nullptr;
+ if (!container_offset_mapping)
+ return container_object_->ComputedName().length();
+ const base::span<const NGOffsetMappingUnit> mapping_units =
+ container_offset_mapping->GetMappingUnitsForNode(*container_node);
+ if (mapping_units.empty())
+ return container_object_->ComputedName().length();
+ return int{mapping_units.back().TextContentEnd() -
+ mapping_units.front().TextContentStart()};
}
TextAffinity AXPosition::Affinity() const {
@@ -455,11 +494,23 @@ bool AXPosition::IsValid(String* failure_reason) const {
return false;
}
+ const Document* document = container_object_->GetDocument();
+ DCHECK(document->IsActive());
+ DCHECK(!document->NeedsLayoutTreeUpdate());
+ if (!document->IsActive() || document->NeedsLayoutTreeUpdate()) {
+ if (failure_reason) {
+ *failure_reason =
+ "\nPosition invalid: document is either not active or it needs "
+ "layout tree update.";
+ }
+ return false;
+ }
+
if (IsTextPosition()) {
if (text_offset_or_child_index_ > MaxTextOffset()) {
if (failure_reason) {
*failure_reason = String::Format(
- "\nPosition invalid: text offset too large.\n%d vs. %d",
+ "\nPosition invalid: text offset too large.\n%d vs. %d.",
text_offset_or_child_index_, MaxTextOffset());
}
return false;
@@ -469,7 +520,7 @@ bool AXPosition::IsValid(String* failure_reason) const {
container_object_->ChildCountIncludingIgnored()) {
if (failure_reason) {
*failure_reason = String::Format(
- "\nPosition invalid: child index too large.\n%d vs. %d",
+ "\nPosition invalid: child index too large.\n%d vs. %d.",
text_offset_or_child_index_,
container_object_->ChildCountIncludingIgnored());
}
@@ -477,8 +528,6 @@ bool AXPosition::IsValid(String* failure_reason) const {
}
}
- DCHECK(container_object_->GetDocument()->IsActive());
- DCHECK(!container_object_->GetDocument()->NeedsLayoutTreeUpdate());
#if DCHECK_IS_ON()
DCHECK_EQ(container_object_->GetDocument()->DomTreeVersion(),
dom_tree_version_);
@@ -688,7 +737,7 @@ const AXPosition AXPosition::AsValidDOMPosition(
// positions are also considered to be virtual since they don't have an
// associated DOM node.
- // More Explaination:
+ // In more detail:
// If the child after a tree position doesn't have an associated node in the
// DOM tree, we adjust to the next or previous position because a
// corresponding child node will not be found in the DOM tree. We need a
@@ -714,12 +763,15 @@ const AXPosition AXPosition::AsValidDOMPosition(
(child &&
(!child->GetNode() || child->GetNode()->IsMarkerPseudoElement() ||
child->IsMockObject() || child->IsVirtualObject()))) {
- switch (adjustment_behavior) {
- case AXPositionAdjustmentBehavior::kMoveRight:
- return CreateNextPosition().AsValidDOMPosition(adjustment_behavior);
- case AXPositionAdjustmentBehavior::kMoveLeft:
- return CreatePreviousPosition().AsValidDOMPosition(adjustment_behavior);
- }
+ AXPosition result;
+ if (adjustment_behavior == AXPositionAdjustmentBehavior::kMoveRight)
+ result = CreateNextPosition();
+ else
+ result = CreatePreviousPosition();
+
+ if (result && result != *this)
+ return result.AsValidDOMPosition(adjustment_behavior);
+ return {};
}
// At this point, if a DOM node is associated with our container, then the
@@ -846,20 +898,75 @@ const PositionWithAffinity AXPosition::ToPositionWithAffinity(
affinity_);
}
- // TODO(nektar): Use LayoutNG offset mapping instead of |TextIterator|.
- TextIteratorBehavior::Builder iterator_builder;
- const TextIteratorBehavior text_iterator_behavior =
- iterator_builder.SetDoesNotEmitSpaceBeyondRangeEnd(true).Build();
- const auto first_position = Position::FirstPositionInNode(*container_node);
- const auto last_position = Position::LastPositionInNode(*container_node);
- CharacterIterator character_iterator(first_position, last_position,
- text_iterator_behavior);
- unsigned text_offset_in_container =
- adjusted_position.container_object_->TextOffsetInContainer(
+ // If NGOffsetMapping supports it, convert from a text offset, which may have
+ // white space collapsed, to a DOM offset which should have uncompressed white
+ // space. NGOffsetMapping supports layout text, layout replaced, ruby runs,
+ // list markers, and layout block flow at inline-level, i.e. "display=inline"
+ // or "display=inline-block". It also supports out-of-flow elements, which
+ // should not be relevant to text positions in the accessibility tree.
+ const LayoutObject* layout_object = container_node->GetLayoutObject();
+ // TODO(crbug.com/567964): LayoutObject::IsAtomicInlineLevel() also includes
+ // block-level replaced elements. We need to explicitly exclude them via
+ // LayoutObject::IsInline().
+ const bool supports_ng_offset_mapping =
+ layout_object &&
+ ((layout_object->IsInline() && layout_object->IsAtomicInlineLevel()) ||
+ layout_object->IsText());
+ const NGOffsetMapping* container_offset_mapping = nullptr;
+ if (supports_ng_offset_mapping) {
+ LayoutBlockFlow* formatting_context =
+ NGOffsetMapping::GetInlineFormattingContextOf(*layout_object);
+ container_offset_mapping =
+ formatting_context ? NGInlineNode::GetOffsetMapping(formatting_context)
+ : nullptr;
+ }
+
+ if (!container_offset_mapping) {
+ // We are unable to compute the text offset in the accessibility tree that
+ // corresponds to the DOM offset. We do the next best thing by returning
+ // either the first or the last DOM position in |container_node| based on
+ // the |adjustment_behavior|.
+ switch (adjustment_behavior) {
+ case AXPositionAdjustmentBehavior::kMoveRight:
+ return PositionWithAffinity(
+ Position::LastPositionInNode(*container_node), affinity_);
+ case AXPositionAdjustmentBehavior::kMoveLeft:
+ return PositionWithAffinity(
+ Position::FirstPositionInNode(*container_node), affinity_);
+ }
+ }
+
+ int text_offset_in_formatting_context =
+ adjusted_position.container_object_->TextOffsetInFormattingContext(
adjusted_position.TextOffset());
- const EphemeralRange range = character_iterator.CalculateCharacterSubrange(
- 0, text_offset_in_container);
- return PositionWithAffinity(range.EndPosition(), affinity_);
+ DCHECK_GE(text_offset_in_formatting_context, 0);
+
+ // An "after text" position in the accessibility tree should map to a text
+ // position in the DOM tree that is after the DOM node's text, but before any
+ // collapsed white space at the node's end. In all other cases, the text
+ // offset in the accessibility tree should be translated to a DOM offset that
+ // is after any collapsed white space. For example, look at the inline text
+ // box with the word "Hello" and observe how the white space in the DOM, both
+ // before and after the word, is mapped from the equivalent accessibility
+ // position.
+ //
+ // AX text position in "InlineTextBox" name="Hello", 0
+ // DOM position #text " Hello "@offsetInAnchor[3]
+ // AX text position in "InlineTextBox" name="Hello", 5
+ // DOM position #text " Hello "@offsetInAnchor[8]
+ Position dom_position =
+ adjusted_position.TextOffset() < adjusted_position.MaxTextOffset()
+ ? container_offset_mapping->GetLastPosition(
+ static_cast<unsigned int>(text_offset_in_formatting_context))
+ : container_offset_mapping->GetFirstPosition(
+ static_cast<unsigned int>(text_offset_in_formatting_context));
+
+ // When there is no uncompressed white space at the end of our
+ // |container_node|, and this is an "after text" position, we might get back
+ // the NULL position if this is the last node in the DOM.
+ if (dom_position.IsNull())
+ dom_position = Position::LastPositionInNode(*container_node);
+ return PositionWithAffinity(dom_position, affinity_);
}
const Position AXPosition::ToPosition(
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h
index 58c23bf2152..e6d172670a4 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h
@@ -191,6 +191,8 @@ class MODULES_EXPORT AXPosition final {
uint64_t dom_tree_version_;
uint64_t style_version_;
#endif
+
+ friend class AXSelection;
};
MODULES_EXPORT bool operator==(const AXPosition&, const AXPosition&);
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 ef01b76b82d..56a29df6f05 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
@@ -1681,10 +1681,15 @@ TEST_F(AccessibilityTest, PositionInInvalidMapLayout) {
TEST_P(ParameterizedAccessibilityTest,
ToPositionWithAffinityWithMultipleInlineTextBoxes) {
+ // This test expects the starting offset of the last InlineTextBox object to
+ // equate the sum of the previous inline text boxes' length, without the
+ // collapsed white-spaces.
+ //
// "&#10" is a Line Feed ("\n").
SetBodyInnerHTML(
R"HTML(<style>p { white-space: pre-line; }</style>
<p id="paragraph">Hello &#10; world</p>)HTML");
+
const Node* text = GetElementById("paragraph")->firstChild();
ASSERT_NE(nullptr, text);
ASSERT_TRUE(text->IsTextNode());
@@ -1695,16 +1700,19 @@ TEST_P(ParameterizedAccessibilityTest,
ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue());
ax_static_text->LoadInlineTextBoxes();
- ASSERT_EQ(3, ax_static_text->ChildCountIncludingIgnored());
+ ASSERT_EQ(3, ax_static_text->UnignoredChildCount());
- // This test expects the starting offset of the last InlineTextBox object to
- // equates the sum of the previous inline text boxes length, without the
- // collapsed white-spaces.
- const auto ax_position = AXPosition::CreatePositionBeforeObject(
- *(ax_static_text->LastChildIncludingIgnored()));
+ // The last inline text box should be:
+ // "InlineTextBox" name="world"
+ const AXObject* ax_last_inline_box =
+ ax_static_text->LastChildIncludingIgnored();
+ const auto ax_position =
+ AXPosition::CreatePositionBeforeObject(*ax_last_inline_box);
const auto position = ax_position.ToPositionWithAffinity();
- EXPECT_EQ(LayoutNGEnabled() ? 7 : 6,
- position.GetPosition().OffsetInContainerNode());
+ // The resulting DOM position should be:
+ // DOM position #text "Hello \n world"@offsetInAnchor[8]
+ ASSERT_TRUE(position.GetPosition().IsOffsetInAnchor());
+ EXPECT_EQ(8, position.GetPosition().OffsetInContainerNode());
}
} // namespace test
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 1897c42647e..cb5f72fe40f 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
@@ -24,11 +24,13 @@ void AXRelationCache::Init() {
if (!id.IsEmpty())
all_previously_seen_label_target_ids_.insert(id);
+ // Ensure correct ancestor chains even when not all AXObject's in the
+ // document are created, e.g. in the devtools accessibility panel.
+ // Defers adding aria-owns targets as children of their new parents,
+ // and to the relation cache, until the appropriate document lifecycle.
if (element.FastHasAttribute(html_names::kAriaOwnsAttr)) {
- if (AXObject* obj = object_cache_->GetOrCreate(&element)) {
- obj->ClearChildren();
- obj->AddChildren();
- }
+ object_cache_->HandleAttributeChanged(html_names::kAriaOwnsAttr,
+ &element);
}
}
}
@@ -322,7 +324,6 @@ void AXRelationCache::ChildrenChanged(AXObject* object) {
}
void AXRelationCache::TextChanged(AXObject* object) {
- object->TextChanged();
object_cache_->PostNotification(object, ax::mojom::Event::kTextChanged);
}
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 877ddabf147..ae9317419bf 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.cc
@@ -7,6 +7,7 @@
#include "third_party/blink/renderer/core/dom/events/event.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/editing/ephemeral_range.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/position_with_affinity.h"
@@ -329,6 +330,24 @@ const SelectionInDOMTree AXSelection::AsSelection(
return selection_builder.Build();
}
+void AXSelection::UpdateSelectionIfNecessary() {
+ Document* document = base_.ContainerObject()->GetDocument();
+ if (!document)
+ return;
+
+ LocalFrameView* view = document->View();
+ if (!view || !view->LayoutPending())
+ return;
+
+ document->UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
+#if DCHECK_IS_ON()
+ base_.dom_tree_version_ = extent_.dom_tree_version_ = dom_tree_version_ =
+ document->DomTreeVersion();
+ base_.style_version_ = extent_.style_version_ = style_version_ =
+ document->StyleVersion();
+#endif // DCHECK_IS_ON()
+}
+
bool AXSelection::Select(const AXSelectionBehavior selection_behavior) {
if (!IsValid()) {
NOTREACHED() << "Trying to select an invalid accessibility selection.";
@@ -339,21 +358,24 @@ bool AXSelection::Select(const AXSelectionBehavior selection_behavior) {
AsTextControlSelection();
if (text_control_selection.has_value()) {
DCHECK_LE(text_control_selection->start, text_control_selection->end);
- TextControlElement& text_control =
- ToTextControl(*base_.ContainerObject()->GetNode());
+ TextControlElement& text_control = ToTextControl(
+ *base_.ContainerObject()->GetNativeTextControlAncestor()->GetNode());
if (!text_control.SetSelectionRange(text_control_selection->start,
text_control_selection->end,
text_control_selection->direction)) {
return false;
}
+ // TextControl::SetSelectionRange deliberately does not set focus. But if
+ // we're updating the selection, the text control should be focused.
ScheduleSelectEvent(text_control);
+ text_control.focus();
return true;
}
- const SelectionInDOMTree selection = AsSelection(selection_behavior);
- DCHECK(selection.AssertValid());
- Document* document = selection.Base().GetDocument();
+ const SelectionInDOMTree old_selection = AsSelection(selection_behavior);
+ DCHECK(old_selection.AssertValid());
+ Document* document = old_selection.Base().GetDocument();
if (!document) {
NOTREACHED() << "Valid DOM selections should have an attached document.";
return false;
@@ -371,46 +393,32 @@ bool AXSelection::Select(const AXSelectionBehavior selection_behavior) {
// See the following section in the Selection API Specification:
// https://w3c.github.io/selection-api/#selectstart-event
- if (DispatchSelectStart(selection.Extent().ComputeContainerNode()) !=
+ if (DispatchSelectStart(old_selection.Base().ComputeContainerNode()) !=
DispatchEventResult::kNotCanceled) {
return false;
}
+ UpdateSelectionIfNecessary();
+ if (!IsValid())
+ return false;
+
+ // Dispatching the "selectstart" event could potentially change the document
+ // associated with the current frame.
+ if (!frame_selection.IsAvailable())
+ return false;
+
+ // Re-retrieve the SelectionInDOMTree in case a DOM mutation took place.
+ // That way it will also have the updated DOM tree and Style versions,
+ // and the SelectionTemplate checks for each won't fail.
+ const SelectionInDOMTree selection = AsSelection(selection_behavior);
+
SetSelectionOptions::Builder options_builder;
options_builder.SetIsDirectional(true)
.SetShouldCloseTyping(true)
.SetShouldClearTypingStyle(true)
.SetSetSelectionBy(SetSelectionBy::kUser);
- frame_selection.ClearDocumentCachedRange();
- frame_selection.SetSelection(selection, options_builder.Build());
-
- // Cache the newly created document range. This doesn't affect the already
- // applied selection. Note that DOM's |Range| object has a start and an end
- // container that need to be in DOM order. See the DOM specification for more
- // information: https://dom.spec.whatwg.org/#interface-range
- Range* range = Range::Create(*document);
- if (selection.Extent().IsNull()) {
- DCHECK(selection.Base().IsNotNull())
- << "AX selections converted to DOM selections should have at least one "
- "endpoint non-null.\n"
- << *this << '\n'
- << selection;
- range->setStart(selection.Base().ComputeContainerNode(),
- selection.Base().ComputeOffsetInContainerNode());
- range->setEnd(selection.Base().ComputeContainerNode(),
- selection.Base().ComputeOffsetInContainerNode());
- } else if (selection.Base() < selection.Extent()) {
- range->setStart(selection.Base().ComputeContainerNode(),
- selection.Base().ComputeOffsetInContainerNode());
- range->setEnd(selection.Extent().ComputeContainerNode(),
- selection.Extent().ComputeOffsetInContainerNode());
- } else {
- range->setStart(selection.Extent().ComputeContainerNode(),
- selection.Extent().ComputeOffsetInContainerNode());
- range->setEnd(selection.Base().ComputeContainerNode(),
- selection.Base().ComputeOffsetInContainerNode());
- }
- frame_selection.CacheRangeOfDocument(range);
+ frame_selection.SetSelectionForAccessibility(selection,
+ options_builder.Build());
return true;
}
@@ -423,19 +431,23 @@ String AXSelection::ToString() const {
base::Optional<AXSelection::TextControlSelection>
AXSelection::AsTextControlSelection() const {
if (!IsValid() || !base_.IsTextPosition() || !extent_.IsTextPosition() ||
- base_.ContainerObject() != extent_.ContainerObject() ||
- !base_.ContainerObject()->IsNativeTextControl() ||
- !IsTextControl(base_.ContainerObject()->GetNode())) {
+ base_.ContainerObject() != extent_.ContainerObject()) {
return {};
}
+ const AXObject* text_control =
+ base_.ContainerObject()->GetNativeTextControlAncestor();
+ if (!text_control)
+ return {};
+
+ DCHECK(IsTextControl(text_control->GetNode()));
+
if (base_ <= extent_) {
return TextControlSelection(base_.TextOffset(), extent_.TextOffset(),
kSelectionHasForwardDirection);
- } else {
- return TextControlSelection(extent_.TextOffset(), base_.TextOffset(),
- kSelectionHasBackwardDirection);
}
+ return TextControlSelection(extent_.TextOffset(), base_.TextOffset(),
+ kSelectionHasBackwardDirection);
}
bool operator==(const AXSelection& a, const AXSelection& b) {
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 8f3a5e4d344..713e6b804e5 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h
@@ -94,6 +94,10 @@ class MODULES_EXPORT AXSelection final {
AXSelection();
+ // If a layout is pending, update the style and layout along with the DOM
+ // tree and style versions of the AXSelection and associated AXPositions.
+ void UpdateSelectionIfNecessary();
+
// 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|.
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 9be5de17e5e..06f217eee8f 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
@@ -83,10 +83,11 @@ TEST_F(AccessibilitySelectionTest, FromCurrentSelection) {
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hel^lo.>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: How are you?>\n|",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hel^lo.>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: How are you?>\n|",
GetSelectionText(ax_selection));
}
@@ -105,20 +106,24 @@ TEST_F(AccessibilitySelectionTest, FromCurrentSelectionSelectAll) {
ASSERT_TRUE(ax_selection.IsValid());
ASSERT_FALSE(ax_selection.Base().IsTextPosition());
- EXPECT_EQ(GetAXRootObject(), ax_selection.Base().ContainerObject());
+
+ AXObject* html_object = GetAXRootObject()->ChildAtIncludingIgnored(0);
+ ASSERT_NE(nullptr, html_object);
+ EXPECT_EQ(html_object, ax_selection.Base().ContainerObject());
EXPECT_EQ(0, ax_selection.Base().ChildIndex());
ASSERT_FALSE(ax_selection.Extent().IsTextPosition());
- EXPECT_EQ(GetAXRootObject(), ax_selection.Extent().ContainerObject());
- EXPECT_EQ(GetAXRootObject()->ChildCountIncludingIgnored(),
+ EXPECT_EQ(html_object, ax_selection.Extent().ContainerObject());
+ EXPECT_EQ(html_object->ChildCountIncludingIgnored(),
ax_selection.Extent().ChildIndex());
EXPECT_EQ(
- "^++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hello.>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: How are you?>\n|",
+ "++<GenericContainer>\n"
+ "^++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hello.>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: How are you?>\n|",
GetSelectionText(ax_selection));
}
@@ -200,10 +205,11 @@ TEST_F(AccessibilitySelectionTest, CancelSelect) {
EXPECT_FALSE(Selection().GetSelectionInDOMTree().IsNone());
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hel^lo.>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: How are you?>\n|",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hel^lo.>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: How are you?>\n|",
GetSelectionText(AXSelection::FromCurrentSelection(GetDocument())));
}
@@ -260,8 +266,9 @@ TEST_F(AccessibilitySelectionTest, SetSelectionInText) {
EXPECT_EQ(5, dom_selection.Extent().OffsetInContainerNode());
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hel^lo|>\n",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hel^lo|>\n",
GetSelectionText(ax_selection));
}
@@ -291,8 +298,9 @@ TEST_F(AccessibilitySelectionTest, SetSelectionInTextWithWhiteSpace) {
EXPECT_EQ(10, dom_selection.Extent().OffsetInContainerNode());
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hel^lo|>\n",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hel^lo|>\n",
GetSelectionText(ax_selection));
}
@@ -335,10 +343,11 @@ TEST_F(AccessibilitySelectionTest, SetSelectionAcrossLineBreak) {
// selection focus marker '|' should be after it.
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hello>\n"
- "^++++++<LineBreak: \n>\n"
- "|++++++<StaticText: |How are you.>\n",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hello>\n"
+ "^++++++++<LineBreak: \n>\n"
+ "|++++++++<StaticText: |How are you.>\n",
GetSelectionText(ax_selection));
}
@@ -383,10 +392,11 @@ TEST_F(AccessibilitySelectionTest, SetSelectionAcrossLineBreakInEditableText) {
// selection focus marker '|' should be after it.
EXPECT_EQ(
"++<GenericContainer>\n"
- "++++<Paragraph>\n"
- "++++++<StaticText: Hello>\n"
- "^++++++<LineBreak: \n>\n"
- "|++++++<StaticText: |How are you.>\n",
+ "++++<GenericContainer>\n"
+ "++++++<Paragraph>\n"
+ "++++++++<StaticText: Hello>\n"
+ "^++++++++<LineBreak: \n>\n"
+ "|++++++++<StaticText: |How are you.>\n",
GetSelectionText(ax_selection));
}
@@ -476,15 +486,16 @@ TEST_F(AccessibilitySelectionTest, SetSelectionInDisplayNone) {
// to DOM selections.
const std::string selection_text(
"++<GenericContainer>\n"
- "++++<Main>\n"
- "++++++<Paragraph>\n"
- "++++++++<StaticText: Before display:none.>\n"
- "++++++<Paragraph: Display:none 1.>\n"
- "^++++++<Paragraph>\n"
- "++++++++<StaticText: In between two display:none elements.>\n"
- "++++++<Paragraph: Display:none 2.>\n"
- "|++++++<Paragraph>\n"
- "++++++++<StaticText: After display:none.>\n");
+ "++++<GenericContainer>\n"
+ "++++++<Main>\n"
+ "++++++++<Paragraph>\n"
+ "++++++++++<StaticText: Before display:none.>\n"
+ "++++++++<Paragraph>\n"
+ "^++++++++<Paragraph>\n"
+ "++++++++++<StaticText: In between two display:none elements.>\n"
+ "++++++++<Paragraph>\n"
+ "|++++++++<Paragraph>\n"
+ "++++++++++<StaticText: After display:none.>\n");
EXPECT_EQ(selection_text, GetSelectionText(ax_selection_shrink));
EXPECT_EQ(selection_text, GetSelectionText(ax_selection_extend));
}
@@ -572,27 +583,29 @@ TEST_P(ParameterizedAccessibilitySelectionTest, SetSelectionAroundListBullet) {
if (LayoutNGEnabled()) {
expectations =
"++<GenericContainer>\n"
- "++++<Main>\n"
- "++++++<List>\n"
- "++++++++<ListItem>\n"
- "++++++++++<ListMarker: \xE2\x80\xA2 >\n"
- "^++++++++++++<StaticText: ^\xE2\x80\xA2 >\n"
- "++++++++++<StaticText: Item 1.>\n"
- "++++++++<ListItem>\n"
- "++++++++++<ListMarker: \xE2\x80\xA2 >\n"
- "++++++++++++<StaticText: \xE2\x80\xA2 >\n"
- "++++++++++<StaticText: Item 2.|>\n";
+ "++++<GenericContainer>\n"
+ "++++++<Main>\n"
+ "++++++++<List>\n"
+ "++++++++++<ListItem>\n"
+ "++++++++++++<ListMarker: \xE2\x80\xA2 >\n"
+ "^++++++++++++++<StaticText: ^\xE2\x80\xA2 >\n"
+ "++++++++++++<StaticText: Item 1.>\n"
+ "++++++++++<ListItem>\n"
+ "++++++++++++<ListMarker: \xE2\x80\xA2 >\n"
+ "++++++++++++++<StaticText: \xE2\x80\xA2 >\n"
+ "++++++++++++<StaticText: Item 2.|>\n";
} else {
expectations =
"++<GenericContainer>\n"
- "++++<Main>\n"
- "++++++<List>\n"
- "++++++++<ListItem>\n"
- "++++++++++<ListMarker: \xE2\x80\xA2 >\n"
- "^++++++++++<StaticText: Item 1.>\n"
- "++++++++<ListItem>\n"
- "++++++++++<ListMarker: \xE2\x80\xA2 >\n"
- "++++++++++<StaticText: Item 2.|>\n";
+ "++++<GenericContainer>\n"
+ "++++++<Main>\n"
+ "++++++++<List>\n"
+ "++++++++++<ListItem>\n"
+ "++++++++++++<ListMarker: \xE2\x80\xA2 >\n"
+ "^++++++++++++<StaticText: Item 1.>\n"
+ "++++++++++<ListItem>\n"
+ "++++++++++++<ListMarker: \xE2\x80\xA2 >\n"
+ "++++++++++++<StaticText: Item 2.|>\n";
}
// The |AXSelection| should remain unaffected by any shrinking and should
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc
index f956f889c73..ed640990482 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc
@@ -83,7 +83,9 @@ void AXSlider::AddChildren() {
AXObjectCacheImpl& cache = AXObjectCache();
- AXObject* thumb = cache.Create(ax::mojom::blink::Role::kSliderThumb, this);
+ AXSliderThumb* thumb = static_cast<AXSliderThumb*>(
+ cache.GetOrCreate(ax::mojom::Role::kSliderThumb));
+ thumb->SetParent(this);
// Before actually adding the value indicator to the hierarchy,
// allow the platform to make a final decision about it.
@@ -111,7 +113,7 @@ bool AXSlider::OnNativeSetValueAction(const String& value) {
input->setValue(value, TextFieldEventBehavior::kDispatchInputAndChangeEvent);
- // Fire change event manually, as LayoutSlider::setValueForPosition does.
+ // Fire change event manually, as SliderThumbElement::StopDragging does.
input->DispatchFormControlChangeEvent();
// Dispatching an event could result in changes to the document, like
@@ -137,12 +139,12 @@ LayoutObject* AXSliderThumb::LayoutObjectForRelativeBounds() const {
return nullptr;
LayoutObject* slider_layout_object = parent_->GetLayoutObject();
- if (!slider_layout_object || !slider_layout_object->IsSlider())
+ if (!slider_layout_object)
return nullptr;
Element* thumb_element =
To<Element>(slider_layout_object->GetNode())
->UserAgentShadowRoot()
- ->getElementById(shadow_element_names::SliderThumb());
+ ->getElementById(shadow_element_names::kIdSliderThumb);
DCHECK(thumb_element);
return thumb_element->GetLayoutObject();
}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
index 03304d21c14..9b37988098f 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
@@ -5,9 +5,16 @@
#include "third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h"
#include "third_party/blink/renderer/core/dom/qualified_name.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
+void SetIntAttribute(ax::mojom::blink::IntAttribute attribute,
+ ui::AXNodeData* node_data,
+ const AtomicString& value) {
+ node_data->AddIntAttribute(attribute, value.ToInt());
+}
+
class BoolAttributeSetter : public AXSparseAttributeSetter {
public:
BoolAttributeSetter(AXBoolAttribute attribute) : attribute_(attribute) {}
@@ -26,34 +33,6 @@ class BoolAttributeSetter : public AXSparseAttributeSetter {
}
};
-class IntAttributeSetter : public AXSparseAttributeSetter {
- public:
- IntAttributeSetter(AXIntAttribute attribute) : attribute_(attribute) {}
-
- private:
- AXIntAttribute attribute_;
-
- void Run(const AXObject& obj,
- AXSparseAttributeClient& attribute_map,
- const AtomicString& value) override {
- attribute_map.AddIntAttribute(attribute_, value.ToInt());
- }
-};
-
-class UIntAttributeSetter : public AXSparseAttributeSetter {
- public:
- UIntAttributeSetter(AXUIntAttribute attribute) : attribute_(attribute) {}
-
- private:
- AXUIntAttribute attribute_;
-
- void Run(const AXObject& obj,
- AXSparseAttributeClient& attribute_map,
- const AtomicString& value) override {
- attribute_map.AddUIntAttribute(attribute_, value.ToInt());
- }
-};
-
class StringAttributeSetter : public AXSparseAttributeSetter {
public:
StringAttributeSetter(AXStringAttribute attribute) : attribute_(attribute) {}
@@ -188,26 +167,43 @@ AXSparseAttributeSetterMap& GetSparseAttributeSetterMap() {
ax_sparse_attribute_setter_map.Set(
html_names::kAriaBusyAttr,
new BoolAttributeSetter(AXBoolAttribute::kAriaBusy));
- ax_sparse_attribute_setter_map.Set(
+ }
+ return ax_sparse_attribute_setter_map;
+}
+
+// TODO(meredithl): move the rest of the sparse attributes to this map.
+TempSetterMap& GetTempSetterMap(ui::AXNodeData* node_data) {
+ DEFINE_STATIC_LOCAL(TempSetterMap, temp_setter_map, ());
+ if (temp_setter_map.IsEmpty()) {
+ temp_setter_map.Set(
html_names::kAriaColcountAttr,
- new IntAttributeSetter(AXIntAttribute::kAriaColumnCount));
- ax_sparse_attribute_setter_map.Set(
+ WTF::BindRepeating(&SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaColumnCount));
+ temp_setter_map.Set(
html_names::kAriaColindexAttr,
- new UIntAttributeSetter(AXUIntAttribute::kAriaColumnIndex));
- ax_sparse_attribute_setter_map.Set(
+ WTF::BindRepeating(
+ &SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaCellColumnIndex));
+ temp_setter_map.Set(
html_names::kAriaColspanAttr,
- new UIntAttributeSetter(AXUIntAttribute::kAriaColumnSpan));
- ax_sparse_attribute_setter_map.Set(
+ WTF::BindRepeating(
+ &SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaCellColumnSpan));
+ temp_setter_map.Set(
html_names::kAriaRowcountAttr,
- new IntAttributeSetter(AXIntAttribute::kAriaRowCount));
- ax_sparse_attribute_setter_map.Set(
+ WTF::BindRepeating(&SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaRowCount));
+ temp_setter_map.Set(
html_names::kAriaRowindexAttr,
- new UIntAttributeSetter(AXUIntAttribute::kAriaRowIndex));
- ax_sparse_attribute_setter_map.Set(
+ WTF::BindRepeating(&SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaCellRowIndex));
+ temp_setter_map.Set(
html_names::kAriaRowspanAttr,
- new UIntAttributeSetter(AXUIntAttribute::kAriaRowSpan));
+ WTF::BindRepeating(&SetIntAttribute,
+ ax::mojom::blink::IntAttribute::kAriaCellRowSpan));
}
- return ax_sparse_attribute_setter_map;
+
+ return temp_setter_map;
}
void AXSparseAttributeAOMPropertyClient::AddStringProperty(
@@ -241,13 +237,6 @@ void AXSparseAttributeAOMPropertyClient::AddBooleanProperty(
sparse_attribute_client_.AddBoolAttribute(attribute, value);
}
-void AXSparseAttributeAOMPropertyClient::AddIntProperty(AOMIntProperty property,
- int32_t value) {}
-
-void AXSparseAttributeAOMPropertyClient::AddUIntProperty(
- AOMUIntProperty property,
- uint32_t value) {}
-
void AXSparseAttributeAOMPropertyClient::AddFloatProperty(
AOMFloatProperty property,
float value) {}
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h
index 75f088f5b76..4f0f1bb997c 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/aom/accessible_node_list.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "ui/accessibility/ax_node_data.h"
namespace blink {
@@ -31,8 +32,21 @@ using AXSparseAttributeSetterMap =
// That way we only need to iterate over the list of attributes once,
// rather than calling getAttribute() once for each possible obscure
// accessibility attribute.
+// TODO(meredithl): Migrate this to the temp setter for crbug/1068668
AXSparseAttributeSetterMap& GetSparseAttributeSetterMap();
+// A map from attribute name to a callback that sets the |value| for that
+// attribute on an AXNodeData. This is designed to replace the above sparse
+// attribute setter. This name is temporary, the above name of
+// AXSparseAttributeSetterMap will be used once all sparse attributes are
+// migrated.
+using AXSparseSetterFunc =
+ base::RepeatingCallback<void(ui::AXNodeData* node_data,
+ const AtomicString& value)>;
+using TempSetterMap = HashMap<QualifiedName, AXSparseSetterFunc>;
+
+TempSetterMap& GetTempSetterMap(ui::AXNodeData* node_data);
+
// An implementation of AOMPropertyClient that calls
// AXSparseAttributeClient for an AOM property.
class AXSparseAttributeAOMPropertyClient : public AOMPropertyClient {
@@ -45,8 +59,6 @@ class AXSparseAttributeAOMPropertyClient : public AOMPropertyClient {
void AddStringProperty(AOMStringProperty, const String& value) override;
void AddBooleanProperty(AOMBooleanProperty, bool value) override;
- void AddIntProperty(AOMIntProperty, int32_t value) override;
- void AddUIntProperty(AOMUIntProperty, uint32_t value) override;
void AddFloatProperty(AOMFloatProperty, float value) override;
void AddRelationProperty(AOMRelationProperty,
const AccessibleNode& value) override;
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 15f3abc7d46..e39ebff5b3d 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
@@ -24,16 +24,16 @@
namespace blink {
-using protocol::Accessibility::AXPropertyName;
+using protocol::Maybe;
+using protocol::Response;
using protocol::Accessibility::AXNode;
using protocol::Accessibility::AXNodeId;
using protocol::Accessibility::AXProperty;
-using protocol::Accessibility::AXValueSource;
-using protocol::Accessibility::AXValueType;
+using protocol::Accessibility::AXPropertyName;
using protocol::Accessibility::AXRelatedNode;
using protocol::Accessibility::AXValue;
-using protocol::Maybe;
-using protocol::Response;
+using protocol::Accessibility::AXValueSource;
+using protocol::Accessibility::AXValueType;
namespace AXPropertyNameEnum = protocol::Accessibility::AXPropertyNameEnum;
namespace {
@@ -402,10 +402,6 @@ class SparseAttributeAXPropertyAdapter
}
}
- void AddIntAttribute(AXIntAttribute attribute, int32_t value) override {}
-
- void AddUIntAttribute(AXUIntAttribute attribute, uint32_t value) override {}
-
void AddStringAttribute(AXStringAttribute attribute,
const String& value) override {
switch (attribute) {
@@ -839,6 +835,81 @@ void InspectorAccessibilityAgent::AddChildren(
}
}
+namespace {
+
+void setNameAndRole(const AXObject& ax_object, std::unique_ptr<AXNode>& node) {
+ ax::mojom::blink::Role role = ax_object.RoleValue();
+ node->setRole(CreateRoleNameValue(role));
+ AXObject::NameSources name_sources;
+ String computed_name = ax_object.GetName(&name_sources);
+ std::unique_ptr<AXValue> name =
+ CreateValue(computed_name, AXValueTypeEnum::ComputedString);
+ node->setName(std::move(name));
+}
+
+} // namespace
+
+Response InspectorAccessibilityAgent::queryAXTree(
+ Maybe<int> dom_node_id,
+ Maybe<int> backend_node_id,
+ Maybe<String> object_id,
+ Maybe<String> accessible_name,
+ Maybe<String> role,
+ std::unique_ptr<protocol::Array<AXNode>>* nodes) {
+ Node* root_dom_node = nullptr;
+ Response response = dom_agent_->AssertNode(dom_node_id, backend_node_id,
+ object_id, root_dom_node);
+ if (!response.IsSuccess())
+ return response;
+ Document& document = root_dom_node->GetDocument();
+
+ document.UpdateStyleAndLayout(DocumentUpdateReason::kInspector);
+ DocumentLifecycle::DisallowTransitionScope disallow_transition(
+ document.Lifecycle());
+ AXContext ax_context(document);
+
+ *nodes = std::make_unique<protocol::Array<protocol::Accessibility::AXNode>>();
+ auto& cache = To<AXObjectCacheImpl>(ax_context.GetAXObjectCache());
+ AXObject* root_ax_node = cache.GetOrCreate(root_dom_node);
+
+ auto sought_role = ax::mojom::blink::Role::kUnknown;
+ if (role.isJust())
+ sought_role = AXObject::AriaRoleToWebCoreRole(role.fromJust());
+ const String sought_name = accessible_name.fromMaybe("");
+
+ HeapVector<Member<AXObject>> reachable;
+ reachable.push_back(root_ax_node);
+
+ while (!reachable.IsEmpty()) {
+ AXObject* ax_object = reachable.back();
+ reachable.pop_back();
+ const AXObject::AXObjectVector& children =
+ ax_object->ChildrenIncludingIgnored();
+ reachable.AppendRange(children.rbegin(), children.rend());
+
+ // if querying by name: skip if name of current object does not match.
+ if (accessible_name.isJust() && sought_name != ax_object->ComputedName())
+ continue;
+ // if querying by role: skip if role of current object does not match.
+ if (role.isJust() && sought_role != ax_object->RoleValue())
+ continue;
+ // both name and role are OK, so we can add current object to the result.
+
+ if (ax_object->AccessibilityIsIgnored()) {
+ Node* dom_node = ax_object->GetNode();
+ std::unique_ptr<AXNode> protocol_node =
+ BuildObjectForIgnoredNode(dom_node, ax_object, false, *nodes, cache);
+ setNameAndRole(*ax_object, protocol_node);
+ (*nodes)->push_back(std::move(protocol_node));
+ } else {
+ (*nodes)->push_back(
+ BuildProtocolAXObject(*ax_object, nullptr, false, *nodes, cache));
+ }
+ }
+
+ return Response::Success();
+}
+
void InspectorAccessibilityAgent::EnableAndReset() {
enabled_.Set(true);
LocalFrame* frame = inspected_frames_->Root();
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h
index 9a09e8770e5..ab973dad456 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h
+++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h
@@ -47,6 +47,14 @@ class MODULES_EXPORT InspectorAccessibilityAgent
protocol::Response getFullAXTree(
std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*)
override;
+ protocol::Response queryAXTree(
+ protocol::Maybe<int> dom_node_id,
+ protocol::Maybe<int> backend_node_id,
+ protocol::Maybe<String> object_id,
+ protocol::Maybe<String> accessibleName,
+ protocol::Maybe<String> role,
+ std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*)
+ override;
private:
// Unconditionally enables the agent, even if |enabled_.Get()==true|.
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc
index 666729ca020..4d541ef20ea 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.cc
@@ -8,6 +8,7 @@
#include <iterator>
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/renderer/core/dom/character_data.h"
#include "third_party/blink/renderer/core/dom/container_node.h"
#include "third_party/blink/renderer/core/dom/node.h"
@@ -346,7 +347,7 @@ AccessibilitySelectionTest::AccessibilitySelectionTest(
void AccessibilitySelectionTest::SetUp() {
AccessibilityTest::SetUp();
- RuntimeEnabledFeatures::SetAccessibilityExposeHTMLElementEnabled(false);
+ RuntimeEnabledFeatures::SetAccessibilityExposeHTMLElementEnabled(true);
}
std::string AccessibilitySelectionTest::GetCurrentSelectionText() const {
@@ -442,6 +443,11 @@ void AccessibilitySelectionTest::RunSelectionTest(
}
EXPECT_EQ(ax_file_contents, actual_ax_file_contents);
+
+ // Uncomment these lines to write the output to the expectations file.
+ // TODO(dmazzoni): make this a command-line parameter.
+ // if (ax_file_contents != actual_ax_file_contents)
+ // base::WriteFile(WebStringToFilePath(ax_file), actual_ax_file_contents);
}
ParameterizedAccessibilitySelectionTest::
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 b2dc90fd6a8..9683c40a899 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
@@ -21,10 +21,15 @@ AccessibilityTest::AccessibilityTest(LocalFrameClient* local_frame_client)
void AccessibilityTest::SetUp() {
RenderingTest::SetUp();
RuntimeEnabledFeatures::SetAccessibilityExposeHTMLElementEnabled(true);
+ RuntimeEnabledFeatures::
+ SetAccessibilityUseAXPositionForDocumentMarkersEnabled(true);
ax_context_ = std::make_unique<AXContext>(GetDocument());
}
AXObjectCacheImpl& AccessibilityTest::GetAXObjectCache() const {
+ DCHECK(GetDocument().View());
+ GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(
+ DocumentUpdateReason::kAccessibility);
auto* ax_object_cache =
To<AXObjectCacheImpl>(GetDocument().ExistingAXObjectCache());
DCHECK(ax_object_cache);
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/aria-hidden-ax.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/aria-hidden-ax.txt
index ec18cacd126..99cbf9e188a 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/aria-hidden-ax.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/aria-hidden-ax.txt
@@ -3,14 +3,15 @@
AXSelection from AX object anchored position in "Main": "", 1 to AX object anchored position in "Main": "", 4
================================================================================
++<GenericContainer>
-++++<Main>
-++++++<Paragraph>
-++++++++<StaticText: Before aria-hidden.>
-^++++++<Paragraph>
-++++++++<StaticText: Aria-hidden 1.>
-++++++<Paragraph>
-++++++++<StaticText: In the middle of aria-hidden.>
-++++++<Paragraph>
-++++++++<StaticText: Aria-hidden 2.>
-|++++++<Paragraph>
-++++++++<StaticText: After aria-hidden.>
+++++<GenericContainer>
+++++++<Main>
+++++++++<Paragraph>
+++++++++++<StaticText: Before aria-hidden.>
+^++++++++<Paragraph>
+++++++++++<StaticText: Aria-hidden 1.>
+++++++++<Paragraph>
+++++++++++<StaticText: In the middle of aria-hidden.>
+++++++++<Paragraph>
+++++++++++<StaticText: Aria-hidden 2.>
+|++++++++<Paragraph>
+++++++++++<StaticText: After aria-hidden.>
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng-disabled.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng-disabled.txt
index 2d576b50a04..19e45d1c470 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng-disabled.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng-disabled.txt
@@ -3,47 +3,49 @@
AXSelection from AX object anchored position in "List": "", 1 to AX object anchored position in "List": "", 3
================================================================================
++<GenericContainer>
-++++<List>
-++++++<ListItem>
-++++++++<ListMarker: 1. >
-++++++++<StaticText: tic>
-^++++++<ListItem>
-++++++++<ListMarker: 2. >
-++++++++<StaticText: tac>
-++++++<ListItem>
-++++++++<ListMarker: 3. >
-++++++++<StaticText: toe>
-|++++<List>
-++++++<ListItem>
-++++++++<StaticText: tic>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: tac>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: toe>
+++++<GenericContainer>
+++++++<List>
+++++++++<ListItem>
+++++++++++<ListMarker: 1. >
+++++++++++<StaticText: tic>
+^++++++++<ListItem>
+++++++++++<ListMarker: 2. >
+++++++++++<StaticText: tac>
+++++++++<ListItem>
+++++++++++<ListMarker: 3. >
+++++++++++<StaticText: toe>
+|++++++<List>
+++++++++<ListItem>
+++++++++++<StaticText: tic>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: tac>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: toe>
================================================================================
AXSelection from AX object anchored position in "GenericContainer": "", 1 to AX object anchored position in "GenericContainer": "", 2
================================================================================
++<GenericContainer>
-++++<List>
-++++++<ListItem>
-++++++++<ListMarker: 1. >
-++++++++<StaticText: tic>
-++++++<ListItem>
-++++++++<ListMarker: 2. >
-++++++++<StaticText: tac>
-++++++<ListItem>
-++++++++<ListMarker: 3. >
-++++++++<StaticText: toe>
-^++++<List>
-++++++<ListItem>
-++++++++<StaticText: tic>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: tac>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: toe>
+++++<GenericContainer>
+++++++<List>
+++++++++<ListItem>
+++++++++++<ListMarker: 1. >
+++++++++++<StaticText: tic>
+++++++++<ListItem>
+++++++++++<ListMarker: 2. >
+++++++++++<StaticText: tac>
+++++++++<ListItem>
+++++++++++<ListMarker: 3. >
+++++++++++<StaticText: toe>
+^++++++<List>
+++++++++<ListItem>
+++++++++++<StaticText: tic>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: tac>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: toe>
| \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng.txt
index e8758ea0143..768359bbf17 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/list-ax-layout-ng.txt
@@ -3,53 +3,55 @@
AXSelection from AX object anchored position in "List": "", 1 to AX object anchored position in "List": "", 3
================================================================================
++<GenericContainer>
-++++<List>
-++++++<ListItem>
-++++++++<ListMarker: 1. >
-++++++++++<StaticText: 1. >
-++++++++<StaticText: tic>
-^++++++<ListItem>
-++++++++<ListMarker: 2. >
-++++++++++<StaticText: 2. >
-++++++++<StaticText: tac>
-++++++<ListItem>
-++++++++<ListMarker: 3. >
-++++++++++<StaticText: 3. >
-++++++++<StaticText: toe>
-|++++<List>
-++++++<ListItem>
-++++++++<StaticText: tic>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: tac>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: toe>
+++++<GenericContainer>
+++++++<List>
+++++++++<ListItem>
+++++++++++<ListMarker: 1. >
+++++++++++++<StaticText: 1. >
+++++++++++<StaticText: tic>
+^++++++++<ListItem>
+++++++++++<ListMarker: 2. >
+++++++++++++<StaticText: 2. >
+++++++++++<StaticText: tac>
+++++++++<ListItem>
+++++++++++<ListMarker: 3. >
+++++++++++++<StaticText: 3. >
+++++++++++<StaticText: toe>
+|++++++<List>
+++++++++<ListItem>
+++++++++++<StaticText: tic>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: tac>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: toe>
================================================================================
AXSelection from AX object anchored position in "GenericContainer": "", 1 to AX object anchored position in "GenericContainer": "", 2
================================================================================
++<GenericContainer>
-++++<List>
-++++++<ListItem>
-++++++++<ListMarker: 1. >
-++++++++++<StaticText: 1. >
-++++++++<StaticText: tic>
-++++++<ListItem>
-++++++++<ListMarker: 2. >
-++++++++++<StaticText: 2. >
-++++++++<StaticText: tac>
-++++++<ListItem>
-++++++++<ListMarker: 3. >
-++++++++++<StaticText: 3. >
-++++++++<StaticText: toe>
-^++++<List>
-++++++<ListItem>
-++++++++<StaticText: tic>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: tac>
-++++++<StaticText: >
-++++++<ListItem>
-++++++++<StaticText: toe>
+++++<GenericContainer>
+++++++<List>
+++++++++<ListItem>
+++++++++++<ListMarker: 1. >
+++++++++++++<StaticText: 1. >
+++++++++++<StaticText: tic>
+++++++++<ListItem>
+++++++++++<ListMarker: 2. >
+++++++++++++<StaticText: 2. >
+++++++++++<StaticText: tac>
+++++++++<ListItem>
+++++++++++<ListMarker: 3. >
+++++++++++++<StaticText: 3. >
+++++++++++<StaticText: toe>
+^++++++<List>
+++++++++<ListItem>
+++++++++++<StaticText: tic>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: tac>
+++++++++<StaticText: >
+++++++++<ListItem>
+++++++++++<StaticText: toe>
| \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt
index 6eff2cebdd8..a272709c2c9 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/paragraph-presentational-ax.txt
@@ -3,10 +3,11 @@
AXSelection from AX text position in "StaticText": "Some text.", 0 to AX object anchored position in "Main": "", 2
================================================================================
++<GenericContainer>
-++++<Main>
-++++++<Presentational>
-^++++++++<StaticText: ^Some text.>
-++++++<GenericContainer>
-|++++++<Paragraph>
-++++++<Paragraph>
-++++++++<StaticText: After presentational paragraph.>
+++++<GenericContainer>
+++++++<Main>
+++++++++<Presentational>
+^++++++++++<StaticText: ^Some text.>
+++++++++<GenericContainer>
+|++++++++<Paragraph>
+++++++++<Paragraph>
+++++++++++<StaticText: After presentational paragraph.>
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/svg-ax.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/svg-ax.txt
index 1f7d0fdd343..8187e3fdfeb 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/svg-ax.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/svg-ax.txt
@@ -4,27 +4,30 @@ AXSelection from AX text position in "StaticText": "Some text. ", 0 to AX text p
================================================================================
++<GenericContainer>
++++<GenericContainer>
-++++++<Paragraph>
-^++++++++<StaticText: ^Some text. >
-++++++++<Image: Square>
-|++++++++<StaticText: | More text.>
+++++++<GenericContainer>
+++++++++<Paragraph>
+^++++++++++<StaticText: ^Some text. >
+++++++++++<Image: Square>
+|++++++++++<StaticText: | More text.>
================================================================================
AXSelection from AX text position in "StaticText": "Some text. ", 10 to AX text position in "StaticText": " More text.", 1
================================================================================
++<GenericContainer>
++++<GenericContainer>
-++++++<Paragraph>
-++++++++<StaticText: Some text.^ >
-++++++++<Image: Square>
-++++++++<StaticText: |More text.>
+++++++<GenericContainer>
+++++++++<Paragraph>
+++++++++++<StaticText: Some text.^ >
+++++++++++<Image: Square>
+++++++++++<StaticText: |More text.>
================================================================================
AXSelection from AX text position in "StaticText": "Some text. ", 11 to AX text position in "StaticText": " More text.", 11
================================================================================
++<GenericContainer>
++++<GenericContainer>
-++++++<Paragraph>
-++++++++<StaticText: Some text. ^>
-++++++++<Image: Square>
-++++++++<StaticText: More text.|>
+++++++<GenericContainer>
+++++++++<Paragraph>
+++++++++++<StaticText: Some text. ^>
+++++++++++<Image: Square>
+++++++++++<StaticText: More text.|>
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/table-ax.txt b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/table-ax.txt
index ce4a68b2394..d37521e6944 100644
--- a/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/table-ax.txt
+++ b/chromium/third_party/blink/renderer/modules/accessibility/testing/data/selection/table-ax.txt
@@ -3,102 +3,106 @@
AXSelection from AX text position in "StaticText": "Sum", 0 to AX text position in "StaticText": "Subtraction", 11
================================================================================
++<GenericContainer>
-++++<Table>
-++++++<Row>
-++++++++<ColumnHeader: Sum>
-^++++++++++<StaticText: ^Sum>
-++++++++<ColumnHeader: Subtraction>
-++++++++++<StaticText: Subtraction|>
-++++++<Row>
-++++++++<Cell: 10>
-++++++++++<StaticText: 10>
-++++++++<Cell: 7>
-++++++++++<StaticText: 7>
-++++++<Row>
-++++++++<Cell: 2>
-++++++++++<StaticText: 2>
-++++++++<Cell: 4>
-++++++++++<StaticText: 4>
-++++++<Row>
-++++++++<Cell: 12>
-++++++++++<StaticText: 12>
-++++++++<Cell: 3>
-++++++++++<StaticText: 3>
+++++<GenericContainer>
+++++++<Table>
+++++++++<Row>
+++++++++++<ColumnHeader: Sum>
+^++++++++++++<StaticText: ^Sum>
+++++++++++<ColumnHeader: Subtraction>
+++++++++++++<StaticText: Subtraction|>
+++++++++<Row>
+++++++++++<Cell: 10>
+++++++++++++<StaticText: 10>
+++++++++++<Cell: 7>
+++++++++++++<StaticText: 7>
+++++++++<Row>
+++++++++++<Cell: 2>
+++++++++++++<StaticText: 2>
+++++++++++<Cell: 4>
+++++++++++++<StaticText: 4>
+++++++++<Row>
+++++++++++<Cell: 12>
+++++++++++++<StaticText: 12>
+++++++++++<Cell: 3>
+++++++++++++<StaticText: 3>
================================================================================
AXSelection from AX text position in "StaticText": "7", 1 to AX text position in "StaticText": "10", 0
================================================================================
++<GenericContainer>
-++++<Table>
-++++++<Row>
-++++++++<ColumnHeader: Sum>
-++++++++++<StaticText: Sum>
-++++++++<ColumnHeader: Subtraction>
-++++++++++<StaticText: Subtraction>
-++++++<Row>
-++++++++<Cell: 10>
-|++++++++++<StaticText: |10>
-++++++++<Cell: 7>
-++++++++++<StaticText: 7^>
-++++++<Row>
-++++++++<Cell: 2>
-++++++++++<StaticText: 2>
-++++++++<Cell: 4>
-++++++++++<StaticText: 4>
-++++++<Row>
-++++++++<Cell: 12>
-++++++++++<StaticText: 12>
-++++++++<Cell: 3>
-++++++++++<StaticText: 3>
+++++<GenericContainer>
+++++++<Table>
+++++++++<Row>
+++++++++++<ColumnHeader: Sum>
+++++++++++++<StaticText: Sum>
+++++++++++<ColumnHeader: Subtraction>
+++++++++++++<StaticText: Subtraction>
+++++++++<Row>
+++++++++++<Cell: 10>
+|++++++++++++<StaticText: |10>
+++++++++++<Cell: 7>
+++++++++++++<StaticText: 7^>
+++++++++<Row>
+++++++++++<Cell: 2>
+++++++++++++<StaticText: 2>
+++++++++++<Cell: 4>
+++++++++++++<StaticText: 4>
+++++++++<Row>
+++++++++++<Cell: 12>
+++++++++++++<StaticText: 12>
+++++++++++<Cell: 3>
+++++++++++++<StaticText: 3>
================================================================================
AXSelection from AX text position in "StaticText": "2", 1 to AX text position in "StaticText": "4", 0
================================================================================
++<GenericContainer>
-++++<Table>
-++++++<Row>
-++++++++<ColumnHeader: Sum>
-++++++++++<StaticText: Sum>
-++++++++<ColumnHeader: Subtraction>
-++++++++++<StaticText: Subtraction>
-++++++<Row>
-++++++++<Cell: 10>
-++++++++++<StaticText: 10>
-++++++++<Cell: 7>
-++++++++++<StaticText: 7>
-++++++<Row>
-++++++++<Cell: 2>
-++++++++++<StaticText: 2^>
-++++++++<Cell: 4>
-|++++++++++<StaticText: |4>
-++++++<Row>
-++++++++<Cell: 12>
-++++++++++<StaticText: 12>
-++++++++<Cell: 3>
-++++++++++<StaticText: 3>
+++++<GenericContainer>
+++++++<Table>
+++++++++<Row>
+++++++++++<ColumnHeader: Sum>
+++++++++++++<StaticText: Sum>
+++++++++++<ColumnHeader: Subtraction>
+++++++++++++<StaticText: Subtraction>
+++++++++<Row>
+++++++++++<Cell: 10>
+++++++++++++<StaticText: 10>
+++++++++++<Cell: 7>
+++++++++++++<StaticText: 7>
+++++++++<Row>
+++++++++++<Cell: 2>
+++++++++++++<StaticText: 2^>
+++++++++++<Cell: 4>
+|++++++++++++<StaticText: |4>
+++++++++<Row>
+++++++++++<Cell: 12>
+++++++++++++<StaticText: 12>
+++++++++++<Cell: 3>
+++++++++++++<StaticText: 3>
================================================================================
AXSelection from AX text position in "StaticText": "12", 0 to AX text position in "StaticText": "3", 1
================================================================================
++<GenericContainer>
-++++<Table>
-++++++<Row>
-++++++++<ColumnHeader: Sum>
-++++++++++<StaticText: Sum>
-++++++++<ColumnHeader: Subtraction>
-++++++++++<StaticText: Subtraction>
-++++++<Row>
-++++++++<Cell: 10>
-++++++++++<StaticText: 10>
-++++++++<Cell: 7>
-++++++++++<StaticText: 7>
-++++++<Row>
-++++++++<Cell: 2>
-++++++++++<StaticText: 2>
-++++++++<Cell: 4>
-++++++++++<StaticText: 4>
-++++++<Row>
-++++++++<Cell: 12>
-^++++++++++<StaticText: ^12>
-++++++++<Cell: 3>
-++++++++++<StaticText: 3|>
+++++<GenericContainer>
+++++++<Table>
+++++++++<Row>
+++++++++++<ColumnHeader: Sum>
+++++++++++++<StaticText: Sum>
+++++++++++<ColumnHeader: Subtraction>
+++++++++++++<StaticText: Subtraction>
+++++++++<Row>
+++++++++++<Cell: 10>
+++++++++++++<StaticText: 10>
+++++++++++<Cell: 7>
+++++++++++++<StaticText: 7>
+++++++++<Row>
+++++++++++<Cell: 2>
+++++++++++++<StaticText: 2>
+++++++++++<Cell: 4>
+++++++++++++<StaticText: 4>
+++++++++<Row>
+++++++++++<Cell: 12>
+^++++++++++++<StaticText: ^12>
+++++++++++<Cell: 3>
+++++++++++++<StaticText: 3|>
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 8c344748e55..3ef1a129082 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
@@ -6,12 +6,12 @@
#include "base/synchronization/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.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/script/classic_script.h"
@@ -148,18 +148,28 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
waitable_event->Signal();
}
+ static bool RunScriptAndGetBoolean(AnimationWorkletGlobalScope* global_scope,
+ const String& script) {
+ ScriptState* script_state =
+ global_scope->ScriptController()->GetScriptState();
+ DCHECK(script_state);
+ v8::Isolate* isolate = script_state->GetIsolate();
+ DCHECK(isolate);
+ ScriptState::Scope scope(script_state);
+
+ ScriptEvaluationResult result =
+ global_scope->ScriptController()->EvaluateAndReturnValue(
+ ScriptSourceCode(script), SanitizeScriptErrors::kSanitize);
+ DCHECK_EQ(result.GetResultType(),
+ ScriptEvaluationResult::ResultType::kSuccess);
+ return ToBoolean(isolate, result.GetSuccessValue(), ASSERT_NO_EXCEPTION);
+ }
+
void RunConstructAndAnimateTestOnWorklet(
WorkerThread* thread,
base::WaitableEvent* waitable_event) {
ASSERT_TRUE(thread->IsCurrentThread());
auto* global_scope = To<AnimationWorkletGlobalScope>(thread->GlobalScope());
- ScriptState* script_state =
- global_scope->ScriptController()->GetScriptState();
- ASSERT_TRUE(script_state);
- v8::Isolate* isolate = script_state->GetIsolate();
- ASSERT_TRUE(isolate);
-
- ScriptState::Scope scope(script_state);
String source_code =
R"JS(
@@ -182,18 +192,12 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
ClassicScript::CreateUnspecifiedScript(ScriptSourceCode(source_code))
->RunScriptOnWorkerOrWorklet(*global_scope));
- v8::Local<v8::Value> constructed_before =
- global_scope->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode("Function('return this')().constructed"),
- SanitizeScriptErrors::kSanitize);
- EXPECT_FALSE(ToBoolean(isolate, constructed_before, ASSERT_NO_EXCEPTION))
+ EXPECT_FALSE(RunScriptAndGetBoolean(
+ global_scope, "Function('return this')().constructed"))
<< "constructor is not invoked";
- v8::Local<v8::Value> animated_before =
- global_scope->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode("Function('return this')().animated"),
- SanitizeScriptErrors::kSanitize);
- EXPECT_FALSE(ToBoolean(isolate, animated_before, ASSERT_NO_EXCEPTION))
+ EXPECT_FALSE(RunScriptAndGetBoolean(global_scope,
+ "Function('return this')().animated"))
<< "animate function is invoked early";
// Passing a new input state with a new animation id should cause the
@@ -209,18 +213,12 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
ProxyClientMutate(state, global_scope);
EXPECT_EQ(output->animations.size(), 1ul);
- v8::Local<v8::Value> constructed_after =
- global_scope->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode("Function('return this')().constructed"),
- SanitizeScriptErrors::kSanitize);
- EXPECT_TRUE(ToBoolean(isolate, constructed_after, ASSERT_NO_EXCEPTION))
+ EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
+ "Function('return this')().constructed"))
<< "constructor is not invoked";
- v8::Local<v8::Value> animated_after =
- global_scope->ScriptController()->EvaluateAndReturnValue(
- ScriptSourceCode("Function('return this')().animated"),
- SanitizeScriptErrors::kSanitize);
- EXPECT_TRUE(ToBoolean(isolate, animated_after, ASSERT_NO_EXCEPTION))
+ EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
+ "Function('return this')().animated"))
<< "animate function is not invoked";
waitable_event->Signal();
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 f8662e3b3d0..1fabe9dac87 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
@@ -178,7 +178,7 @@ TEST_F(WorkletAnimationTest,
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasOverflowClip());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
scrollable_area->SetScrollOffset(ScrollOffset(0, 20),
@@ -295,7 +295,7 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRate) {
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasOverflowClip());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
scrollable_area->SetScrollOffset(ScrollOffset(0, 20),
@@ -351,7 +351,7 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRateWhilePlaying) {
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasOverflowClip());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
@@ -472,7 +472,7 @@ TEST_F(WorkletAnimationTest, ScrollTimelineNewlyInactive) {
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
- ASSERT_TRUE(scroller->HasOverflowClip());
+ ASSERT_TRUE(scroller->IsScrollContainer());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
scrollable_area->SetScrollOffset(ScrollOffset(0, 40),
diff --git a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.idl b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.idl
index a7a5a2c4a11..8a5a44c3072 100644
--- a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.idl
+++ b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.idl
@@ -7,7 +7,7 @@
Exposed=Window
] interface BeforeInstallPromptEvent : Event {
[CallWith=ExecutionContext] constructor(DOMString type, optional BeforeInstallPromptEventInit eventInitDict = {});
- readonly attribute FrozenArray<DOMString> platforms;
+ [HighEntropy=Direct, Measure] readonly attribute FrozenArray<DOMString> platforms;
[CallWith=ScriptState, RaisesException] readonly attribute Promise<AppBannerPromptResult> userChoice;
[CallWith=ScriptState, RaisesException] Promise<void> prompt();
};
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 27e1392cb28..eacf1cb35e1 100644
--- a/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/background_fetch/BUILD.gn
@@ -27,5 +27,8 @@ blink_modules_sources("background_fetch") {
"service_worker_registration_background_fetch.h",
]
- public_deps = [ "//third_party/blink/renderer/modules/service_worker" ]
+ deps = [
+ "//third_party/blink/renderer/modules/cache_storage:cache_storage",
+ "//third_party/blink/renderer/modules/manifest:manifest",
+ ]
}
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 d7c7dce2e35..584e08693c4 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
@@ -9,7 +9,6 @@
#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/heap/handle.h"
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 ee0fb920156..4565c87c9c4 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
@@ -8,6 +8,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_cache_query_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_resource.h"
@@ -336,6 +338,15 @@ const String BackgroundFetchRegistration::result() const {
}
const String BackgroundFetchRegistration::failureReason() const {
+ blink::IdentifiabilityMetricBuilder(GetExecutionContext()->UkmSourceID())
+ .Set(
+ blink::IdentifiableSurface::FromTypeAndToken(
+ blink::IdentifiableSurface::Type::kWebFeature,
+ WebFeature::
+ kV8BackgroundFetchRegistration_FailureReason_AttributeGetter),
+ failure_reason_ ==
+ mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED)
+ .Record(GetExecutionContext()->UkmRecorder());
switch (failure_reason_) {
case mojom::BackgroundFetchFailureReason::NONE:
return "";
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 58adaf1d1ea..96c3a8f29b4 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
@@ -14,7 +14,7 @@
readonly attribute unsigned long long downloadTotal;
readonly attribute unsigned long long downloaded;
readonly attribute BackgroundFetchResult result;
- readonly attribute BackgroundFetchFailureReason failureReason;
+ [HighEntropy, Measure] readonly attribute BackgroundFetchFailureReason failureReason;
readonly attribute boolean recordsAvailable;
attribute EventHandler onprogress;
diff --git a/chromium/third_party/blink/renderer/modules/background_sync/BUILD.gn b/chromium/third_party/blink/renderer/modules/background_sync/BUILD.gn
index da02d094d34..cb3108eadc7 100644
--- a/chromium/third_party/blink/renderer/modules/background_sync/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/background_sync/BUILD.gn
@@ -18,5 +18,4 @@ blink_modules_sources("background_sync") {
"sync_manager.cc",
"sync_manager.h",
]
- deps = [ "//third_party/blink/renderer/modules/service_worker" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc b/chromium/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
index 72e05f1cf65..6be9541b52c 100644
--- a/chromium/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h"
-#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -94,8 +94,10 @@ ScriptPromise PeriodicSyncManager::unregister(ScriptState* script_state,
mojom::blink::PeriodicBackgroundSyncService*
PeriodicSyncManager::GetBackgroundSyncServiceRemote() {
if (!background_sync_service_.is_bound()) {
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- background_sync_service_.BindNewPipeAndPassReceiver(task_runner_));
+ registration_->GetExecutionContext()
+ ->GetBrowserInterfaceBroker()
+ .GetInterface(
+ background_sync_service_.BindNewPipeAndPassReceiver(task_runner_));
}
return background_sync_service_.get();
}
diff --git a/chromium/third_party/blink/renderer/modules/background_sync/sync_manager.cc b/chromium/third_party/blink/renderer/modules/background_sync/sync_manager.cc
index 9011c23011b..42cb8d31822 100644
--- a/chromium/third_party/blink/renderer/modules/background_sync/sync_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/background_sync/sync_manager.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/modules/background_sync/sync_manager.h"
-#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.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"
@@ -25,7 +25,7 @@ SyncManager::SyncManager(ServiceWorkerRegistration* registration,
: registration_(registration),
background_sync_service_(registration->GetExecutionContext()) {
DCHECK(registration);
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+ registration->GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
background_sync_service_.BindNewPipeAndPassReceiver(task_runner));
}
diff --git a/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc b/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
index 1b5e0df0ced..0578e0cdf26 100644
--- a/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
+++ b/chromium/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
@@ -100,19 +100,6 @@ bool NavigatorBeacon::SendBeaconImpl(
*script_state, GetSupplementable()->GetFrame(), url, data_view);
} else if (data.IsBlob()) {
Blob* blob = data.GetAsBlob();
- if (!RuntimeEnabledFeatures::OutOfBlinkCorsEnabled() &&
- !cors::IsCorsSafelistedContentType(blob->type())) {
- UseCounter::Count(context,
- WebFeature::kSendBeaconWithNonSimpleContentType);
- if (RuntimeEnabledFeatures::
- SendBeaconThrowForBlobWithNonSimpleTypeEnabled()) {
- exception_state.ThrowSecurityError(
- "sendBeacon() with a Blob whose type is not any of the "
- "CORS-safelisted values for the Content-Type request header is "
- "disabled temporarily. See http://crbug.com/490015 for details.");
- return false;
- }
- }
allowed = PingLoader::SendBeacon(
*script_state, GetSupplementable()->GetFrame(), url, blob);
} else if (data.IsString()) {
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
index 4433bf5a8bb..22c2f8c582a 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -160,6 +160,13 @@ static void ConvertRequestDeviceOptions(
result->optional_services.push_back(validated_optional_service);
}
}
+
+ if (options->hasOptionalManufacturerData()) {
+ for (const uint16_t manufacturer_code :
+ options->optionalManufacturerData()) {
+ result->optional_manufacturer_data.push_back(manufacturer_code);
+ }
+ }
}
ScriptPromise Bluetooth::getAvailability(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl
index 90d71c919a6..c24a3e69289 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_device.idl
@@ -19,7 +19,7 @@
optional WatchAdvertisementsOptions options = {});
readonly attribute DOMString id;
- readonly attribute DOMString? name;
+ [HighEntropy=Direct, MeasureAs=BluetoothDeviceName] readonly attribute DOMString? name;
readonly attribute BluetoothRemoteGATTServer gatt;
[RuntimeEnabled=WebBluetoothWatchAdvertisements] readonly attribute boolean watchingAdvertisements;
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl
index edb467dc6d1..da8d2fa4462 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.idl
@@ -11,7 +11,7 @@
SecureContext
] interface BluetoothRemoteGATTCharacteristic : EventTarget {
[SameObject] readonly attribute BluetoothRemoteGATTService service;
- [HighEntropy=Direct, MeasureAs=BluetoothRemoteGATTCharacteristic_Uuid] readonly attribute UUID uuid;
+ readonly attribute UUID uuid;
readonly attribute BluetoothCharacteristicProperties properties;
readonly attribute DataView? value;
[RaisesException, CallWith=ScriptState, MeasureAs=WebBluetoothRemoteCharacteristicGetDescriptor] Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl
index f6ad62cd765..8d5faa4e5da 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_descriptor.idl
@@ -12,7 +12,7 @@
SecureContext
] interface BluetoothRemoteGATTDescriptor {
[SameObject] readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
- [HighEntropy=Direct, MeasureAs=BluetoothRemoteGATTDescriptor_Uuid] readonly attribute UUID uuid;
+ readonly attribute UUID uuid;
readonly attribute DataView? value;
[CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRemoteDescriptorReadValue] Promise<DataView> readValue();
[CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRemoteDescriptorWriteValue] Promise<void> writeValue(BufferSource value);
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_service.idl b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_service.idl
index 1cddb9a949f..62de0fa683a 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_service.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_service.idl
@@ -10,7 +10,7 @@
SecureContext
] interface BluetoothRemoteGATTService {
[SameObject] readonly attribute BluetoothDevice device;
- [HighEntropy=Direct, MeasureAs=BluetoothRemoteGATTService_Uuid] readonly attribute UUID uuid;
+ readonly attribute UUID uuid;
readonly attribute boolean isPrimary;
[RaisesException, CallWith=ScriptState, MeasureAs=WebBluetoothRemoteServiceGetCharacteristic] Promise<BluetoothRemoteGATTCharacteristic> getCharacteristic(BluetoothCharacteristicUUID characteristic);
[RaisesException, CallWith=ScriptState, MeasureAs=WebBluetoothRemoteServiceGetCharacteristics] Promise<sequence<BluetoothRemoteGATTCharacteristic>> getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/request_device_options.idl b/chromium/third_party/blink/renderer/modules/bluetooth/request_device_options.idl
index 6987c61bde4..ebc8f956b55 100644
--- a/chromium/third_party/blink/renderer/modules/bluetooth/request_device_options.idl
+++ b/chromium/third_party/blink/renderer/modules/bluetooth/request_device_options.idl
@@ -7,5 +7,6 @@
dictionary RequestDeviceOptions {
sequence<BluetoothLEScanFilterInit> filters;
sequence<BluetoothServiceUUID> optionalServices = [];
+ [RuntimeEnabled=WebBluetoothWatchAdvertisements] sequence<unsigned short> optionalManufacturerData = [];
boolean acceptAllDevices = false;
};
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 a1477288e4c..d28bee4aaf6 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -22,8 +22,11 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_request_init.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_response.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/core/dom/abort_controller.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/fetch/blob_bytes_consumer.h"
#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
#include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
#include "third_party/blink/renderer/core/fetch/request.h"
@@ -76,6 +79,39 @@ bool HasJavascriptMimeType(const Response* response) {
return MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type);
}
+void ValidateRequestForPut(const Request* request,
+ ExceptionState& exception_state) {
+ KURL url(NullURL(), request->url());
+ if (!url.ProtocolIsInHTTPFamily()) {
+ exception_state.ThrowTypeError("Request scheme '" + url.Protocol() +
+ "' is unsupported");
+ return;
+ }
+ if (request->method() != http_names::kGET) {
+ exception_state.ThrowTypeError("Request method '" + request->method() +
+ "' is unsupported");
+ return;
+ }
+ DCHECK(!request->HasBody());
+}
+
+void ValidateResponseForPut(const Response* response,
+ ExceptionState& exception_state) {
+ if (VaryHeaderContainsAsterisk(response)) {
+ exception_state.ThrowTypeError("Vary header contains *");
+ return;
+ }
+ if (response->GetResponse()->InternalStatus() == 206) {
+ exception_state.ThrowTypeError(
+ "Partial response (status code 206) is unsupported");
+ return;
+ }
+ if (response->IsBodyLocked() || response->IsBodyUsed()) {
+ exception_state.ThrowTypeError("Response body is already used");
+ return;
+ }
+}
+
enum class CodeCachePolicy {
// Use the default policy. Currently that policy generates full code cache
// when a script is stored during service worker install.
@@ -138,105 +174,215 @@ bool ShouldGenerateV8CodeCache(ScriptState* script_state,
} // namespace
-// TODO(nhiroki): Unfortunately, we have to go through V8 to wait for the fetch
-// promise. It should be better to achieve this only within C++ world.
-class Cache::FetchResolvedForAdd final : public ScriptFunction {
+// Waits for all expected Responses and their blob bodies to be available.
+class Cache::BarrierCallbackForPutResponse final
+ : public GarbageCollected<BarrierCallbackForPutResponse> {
public:
- // |exception_state| is passed so that the context_type, interface_name and
- // property_name can be copied and then used to construct a new ExceptionState
- // object asynchronously later.
- static v8::Local<v8::Function> Create(
- ScriptState* script_state,
- Cache* cache,
- const String& method_name,
- const HeapVector<Member<Request>>& requests,
- const ExceptionState& exception_state,
- int64_t trace_id) {
- FetchResolvedForAdd* self = MakeGarbageCollected<FetchResolvedForAdd>(
- script_state, cache, method_name, requests, exception_state, trace_id);
- return self->BindToV8Function();
- }
-
- FetchResolvedForAdd(ScriptState* script_state,
- Cache* cache,
- const String& method_name,
- const HeapVector<Member<Request>>& requests,
- const ExceptionState& exception_state,
- int64_t trace_id)
- : ScriptFunction(script_state),
+ BarrierCallbackForPutResponse(ScriptState* script_state,
+ Cache* cache,
+ const String& method_name,
+ const HeapVector<Member<Request>>& request_list,
+ const ExceptionState& exception_state,
+ int64_t trace_id)
+ : resolver_(MakeGarbageCollected<ScriptPromiseResolver>(script_state)),
+ abort_controller_(
+ cache->CreateAbortController(ExecutionContext::From(script_state))),
cache_(cache),
method_name_(method_name),
- requests_(requests),
+ request_list_(request_list),
context_type_(exception_state.Context()),
property_name_(exception_state.PropertyName()),
interface_name_(exception_state.InterfaceName()),
- trace_id_(trace_id) {}
+ trace_id_(trace_id),
+ response_list_(request_list_.size()),
+ blob_list_(request_list_.size()) {}
- ScriptValue Call(ScriptValue value) override {
- TRACE_EVENT_WITH_FLOW0(
- "CacheStorage", "Cache::FetchResolverForAdd::Call",
- TRACE_ID_GLOBAL(trace_id_),
- TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ // Must be called prior to starting the load of any response.
+ ScriptPromise Promise() const { return resolver_->Promise(); }
- ExceptionState exception_state(GetScriptState()->GetIsolate(),
- context_type_, property_name_,
- interface_name_);
- HeapVector<Member<Response>> responses =
- NativeValueTraits<IDLSequence<Response>>::NativeValue(
- GetScriptState()->GetIsolate(), value.V8Value(), exception_state);
- if (exception_state.HadException()) {
- ScriptPromise rejection =
- ScriptPromise::Reject(GetScriptState(), exception_state);
- return ScriptValue(GetScriptState()->GetIsolate(), rejection.V8Value());
+ AbortSignal* Signal() const { return abort_controller_->signal(); }
+
+ void CompletedResponse(int index,
+ Response* response,
+ scoped_refptr<BlobDataHandle> blob) {
+ if (stopped_)
+ return;
+
+ DCHECK(!response_list_[index]);
+ DCHECK(!blob_list_[index]);
+ DCHECK_LT(num_complete_, request_list_.size());
+
+ response_list_[index] = response;
+ blob_list_[index] = std::move(blob);
+ num_complete_ += 1;
+
+ if (num_complete_ == request_list_.size()) {
+ ScriptState* script_state = resolver_->GetScriptState();
+ ExceptionState exception_state(script_state->GetIsolate(), context_type_,
+ property_name_, interface_name_);
+ cache_->PutImpl(resolver_, method_name_, request_list_, response_list_,
+ blob_list_, exception_state, trace_id_);
+ blob_list_.clear();
+ stopped_ = true;
}
+ }
- for (const auto& response : responses) {
- if (!response->ok()) {
- ScriptPromise rejection = ScriptPromise::Reject(
- GetScriptState(),
- V8ThrowException::CreateTypeError(GetScriptState()->GetIsolate(),
- "Request failed"));
- return ScriptValue(GetScriptState()->GetIsolate(), rejection.V8Value());
- }
- if (VaryHeaderContainsAsterisk(response)) {
- ScriptPromise rejection = ScriptPromise::Reject(
- GetScriptState(),
- V8ThrowException::CreateTypeError(GetScriptState()->GetIsolate(),
- "Vary header contains *"));
- return ScriptValue(GetScriptState()->GetIsolate(), rejection.V8Value());
- }
+ void FailedResponse() {
+ ScriptState* state = resolver_->GetScriptState();
+ if (state->ContextIsValid()) {
+ ScriptState::Scope scope(state);
+ resolver_->Reject(V8ThrowDOMException::CreateOrEmpty(
+ state->GetIsolate(), DOMExceptionCode::kNetworkError,
+ method_name_ + " encountered a network error"));
}
+ Stop();
+ }
- ScriptPromise put_promise =
- cache_->PutImpl(GetScriptState(), method_name_, requests_, responses,
- exception_state, trace_id_);
- return ScriptValue(GetScriptState()->GetIsolate(), put_promise.V8Value());
+ void AbortedResponse() {
+ ScriptState* state = resolver_->GetScriptState();
+ if (state->ContextIsValid()) {
+ ScriptState::Scope scope(state);
+ resolver_->Reject(V8ThrowDOMException::CreateOrEmpty(
+ state->GetIsolate(), DOMExceptionCode::kAbortError,
+ method_name_ + " was aborted"));
+ }
+ Stop();
}
- void Trace(Visitor* visitor) const override {
+ void OnError(ScriptValue value) {
+ resolver_->Reject(value);
+ Stop();
+ }
+
+ void OnError(ExceptionState& exception_state) {
+ resolver_->Reject(exception_state);
+ Stop();
+ }
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(resolver_);
+ visitor->Trace(abort_controller_);
visitor->Trace(cache_);
- visitor->Trace(requests_);
- ScriptFunction::Trace(visitor);
+ visitor->Trace(request_list_);
+ visitor->Trace(response_list_);
}
private:
+ void Stop() {
+ if (stopped_)
+ return;
+ abort_controller_->abort();
+ blob_list_.clear();
+ stopped_ = true;
+ }
+
+ Member<ScriptPromiseResolver> resolver_;
+ Member<AbortController> abort_controller_;
Member<Cache> cache_;
const String method_name_;
- HeapVector<Member<Request>> requests_;
+ const HeapVector<Member<Request>> request_list_;
ExceptionState::ContextType context_type_;
const char* property_name_;
const char* interface_name_;
const int64_t trace_id_;
+ HeapVector<Member<Response>> response_list_;
+ WTF::Vector<scoped_refptr<BlobDataHandle>> blob_list_;
+ size_t num_complete_ = 0;
+ bool stopped_ = false;
};
-class Cache::BarrierCallbackForPut final
- : public GarbageCollected<BarrierCallbackForPut> {
+// Waits for a single Response and then loads its body as a blob. This class
+// also performs validation on the Response and triggers a failure if
+// necessary. Passing true for |require_response_ok| will also trigger a
+// failure if the Response status code is not ok. This is necessary for the
+// add/addAll case, but is not used in the put case.
+class Cache::ResponseBodyLoader final
+ : public GarbageCollected<Cache::ResponseBodyLoader>,
+ public FetchDataLoader::Client {
public:
- BarrierCallbackForPut(wtf_size_t number_of_operations,
- Cache* cache,
- const String& method_name,
- ScriptPromiseResolver* resolver,
- int64_t trace_id)
+ ResponseBodyLoader(ScriptState* script_state,
+ BarrierCallbackForPutResponse* barrier_callback,
+ int index,
+ bool require_ok_response,
+ int64_t trace_id)
+ : script_state_(script_state),
+ barrier_callback_(barrier_callback),
+ index_(index),
+ require_ok_response_(require_ok_response),
+ trace_id_(trace_id) {}
+
+ void OnResponse(Response* response, ExceptionState& exception_state) {
+ TRACE_EVENT_WITH_FLOW0(
+ "CacheStorage", "Cache::ResponseBodyLoader::OnResponse",
+ TRACE_ID_GLOBAL(trace_id_),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+
+ if (require_ok_response_ && !response->ok()) {
+ exception_state.ThrowTypeError("Request failed");
+ barrier_callback_->OnError(exception_state);
+ return;
+ }
+
+ ValidateResponseForPut(response, exception_state);
+ if (exception_state.HadException()) {
+ barrier_callback_->OnError(exception_state);
+ return;
+ }
+
+ BodyStreamBuffer* buffer = response->InternalBodyBuffer();
+ if (!buffer) {
+ barrier_callback_->CompletedResponse(index_, response, nullptr);
+ return;
+ }
+
+ response_ = response;
+
+ ExecutionContext* context = ExecutionContext::From(script_state_);
+ fetch_loader_ = FetchDataLoader::CreateLoaderAsBlobHandle(
+ response_->InternalMIMEType(),
+ context->GetTaskRunner(TaskType::kNetworking));
+ buffer->StartLoading(fetch_loader_, this, exception_state);
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(script_state_);
+ visitor->Trace(barrier_callback_);
+ visitor->Trace(response_);
+ visitor->Trace(fetch_loader_);
+ FetchDataLoader::Client::Trace(visitor);
+ }
+
+ private:
+ void DidFetchDataLoadedBlobHandle(
+ scoped_refptr<BlobDataHandle> handle) override {
+ barrier_callback_->CompletedResponse(index_, response_, std::move(handle));
+ }
+
+ void DidFetchDataLoadFailed() override {
+ barrier_callback_->FailedResponse();
+ }
+
+ void Abort() override { barrier_callback_->AbortedResponse(); }
+
+ Member<ScriptState> script_state_;
+ Member<BarrierCallbackForPutResponse> barrier_callback_;
+ const int index_;
+ const bool require_ok_response_;
+ const int64_t trace_id_;
+ Member<Response> response_;
+ Member<FetchDataLoader> fetch_loader_;
+};
+
+// Waits for code cache to be generated and writing to cache_storage to
+// complete.
+class Cache::BarrierCallbackForPutComplete final
+ : public GarbageCollected<BarrierCallbackForPutComplete> {
+ public:
+ BarrierCallbackForPutComplete(wtf_size_t number_of_operations,
+ Cache* cache,
+ const String& method_name,
+ ScriptPromiseResolver* resolver,
+ int64_t trace_id)
: number_of_remaining_operations_(number_of_operations),
cache_(cache),
method_name_(method_name),
@@ -250,7 +396,7 @@ class Cache::BarrierCallbackForPut final
mojom::blink::BatchOperationPtr batch_operation) {
DCHECK_LT(index, batch_operations_.size());
TRACE_EVENT_WITH_FLOW1(
- "CacheStorage", "Cache::BarrierCallbackForPut::OnSuccess",
+ "CacheStorage", "Cache::BarrierCallbackForPutComplete::OnSuccess",
TRACE_ID_GLOBAL(trace_id_),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "batch_operation",
CacheStorageTracedValue(batch_operation));
@@ -275,7 +421,7 @@ class Cache::BarrierCallbackForPut final
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
TRACE_EVENT_WITH_FLOW1(
"CacheStorage",
- "Cache::BarrierCallbackForPut::OnSuccess::Callback",
+ "Cache::BarrierCallbackForPutComplete::OnSuccess::Callback",
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN, "status",
CacheStorageTracedValue(error->value));
if (operation_count > 1) {
@@ -307,11 +453,20 @@ class Cache::BarrierCallbackForPut final
WrapPersistent(cache_.Get())));
}
+ void OnError(ExceptionState& exception_state) {
+ if (!StillActive())
+ return;
+ completed_ = true;
+ resolver_->Reject(exception_state);
+ }
+
void OnError(const String& error_message) {
if (!StillActive())
return;
completed_ = true;
ScriptState* state = resolver_->GetScriptState();
+ if (!state->ContextIsValid())
+ return;
ScriptState::Scope scope(state);
resolver_->Reject(
V8ThrowException::CreateTypeError(state->GetIsolate(), error_message));
@@ -321,9 +476,13 @@ class Cache::BarrierCallbackForPut final
if (!StillActive())
return;
completed_ = true;
- ScriptState::Scope scope(resolver_->GetScriptState());
- resolver_->Reject(
- MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError));
+ ScriptState* state = resolver_->GetScriptState();
+ if (!state->ContextIsValid())
+ return;
+ ScriptState::Scope scope(state);
+ resolver_->Reject(V8ThrowDOMException::CreateOrEmpty(
+ state->GetIsolate(), DOMExceptionCode::kAbortError,
+ method_name_ + " was aborted"));
}
virtual void Trace(Visitor* visitor) const {
@@ -379,48 +538,86 @@ class Cache::BarrierCallbackForPut final
const int64_t trace_id_;
};
-class Cache::BlobHandleCallbackForPut final
- : public GarbageCollected<BlobHandleCallbackForPut>,
- public FetchDataLoader::Client {
+// Used to handle the ScopedFetcher::Fetch promise in AddAllImpl.
+// TODO(nhiroki): Unfortunately, we have to go through V8 to wait for the fetch
+// promise. It should be better to achieve this only within C++ world.
+class Cache::FetchHandler final : public ScriptFunction {
public:
- BlobHandleCallbackForPut(wtf_size_t index,
- BarrierCallbackForPut* barrier_callback,
- Request* request,
- Response* response)
- : index_(index), barrier_callback_(barrier_callback) {
- fetch_api_request_ = request->CreateFetchAPIRequest();
- fetch_api_response_ = response->PopulateFetchAPIResponse(request->url());
+ // |exception_state| is passed so that the context_type, interface_name and
+ // property_name can be copied and then used to construct a new ExceptionState
+ // object asynchronously later.
+ static v8::Local<v8::Function> CreateForResolve(
+ ScriptState* script_state,
+ ResponseBodyLoader* response_loader,
+ BarrierCallbackForPutResponse* barrier_callback,
+ const ExceptionState& exception_state) {
+ FetchHandler* self = MakeGarbageCollected<FetchHandler>(
+ script_state, response_loader, barrier_callback, exception_state);
+ return self->BindToV8Function();
}
- ~BlobHandleCallbackForPut() override = default;
- void DidFetchDataLoadedBlobHandle(
- scoped_refptr<BlobDataHandle> handle) override {
- mojom::blink::BatchOperationPtr batch_operation =
- mojom::blink::BatchOperation::New();
- batch_operation->operation_type = mojom::blink::OperationType::kPut;
- batch_operation->request = std::move(fetch_api_request_);
- batch_operation->response = std::move(fetch_api_response_);
- batch_operation->response->blob = handle;
- barrier_callback_->OnSuccess(index_, std::move(batch_operation));
+ static v8::Local<v8::Function> CreateForReject(
+ ScriptState* script_state,
+ BarrierCallbackForPutResponse* barrier_callback,
+ const ExceptionState& exception_state) {
+ FetchHandler* self = MakeGarbageCollected<FetchHandler>(
+ script_state, /*response_loader=*/nullptr, barrier_callback,
+ exception_state);
+ return self->BindToV8Function();
}
- void DidFetchDataLoadFailed() override {
- barrier_callback_->OnError("network error");
- }
+ FetchHandler(ScriptState* script_state,
+ ResponseBodyLoader* response_loader,
+ BarrierCallbackForPutResponse* barrier_callback,
+ const ExceptionState& exception_state)
+ : ScriptFunction(script_state),
+ response_loader_(response_loader),
+ barrier_callback_(barrier_callback),
+ context_type_(exception_state.Context()),
+ property_name_(exception_state.PropertyName()),
+ interface_name_(exception_state.InterfaceName()) {}
- void Abort() override { barrier_callback_->Abort(); }
+ ScriptValue Call(ScriptValue value) override {
+ // We always resolve undefined from this promise handler since the
+ // promise is never returned to script or chained to another handler.
+ // If we return our real result and an exception occurs then unhandled
+ // promise errors will occur.
+ ScriptValue rtn =
+ ScriptPromise::CastUndefined(GetScriptState()).GetScriptValue();
+
+ // If there is no loader, we were created as a reject handler.
+ if (!response_loader_) {
+ barrier_callback_->OnError(value);
+ return rtn;
+ }
+
+ ExceptionState exception_state(GetScriptState()->GetIsolate(),
+ context_type_, property_name_,
+ interface_name_);
+
+ // Resolve handler, so try to process a Response.
+ Response* response = NativeValueTraits<Response>::NativeValue(
+ GetScriptState()->GetIsolate(), value.V8Value(), exception_state);
+ if (exception_state.HadException())
+ barrier_callback_->OnError(exception_state);
+ else
+ response_loader_->OnResponse(response, exception_state);
+
+ return rtn;
+ }
void Trace(Visitor* visitor) const override {
+ visitor->Trace(response_loader_);
visitor->Trace(barrier_callback_);
- FetchDataLoader::Client::Trace(visitor);
+ ScriptFunction::Trace(visitor);
}
private:
- const wtf_size_t index_;
- Member<BarrierCallbackForPut> barrier_callback_;
-
- mojom::blink::FetchAPIRequestPtr fetch_api_request_;
- mojom::blink::FetchAPIResponsePtr fetch_api_response_;
+ Member<ResponseBodyLoader> response_loader_;
+ Member<BarrierCallbackForPutResponse> barrier_callback_;
+ ExceptionState::ContextType context_type_;
+ const char* property_name_;
+ const char* interface_name_;
};
class Cache::CodeCacheHandleCallbackForPut final
@@ -429,14 +626,16 @@ class Cache::CodeCacheHandleCallbackForPut final
public:
CodeCacheHandleCallbackForPut(ScriptState* script_state,
wtf_size_t index,
- BarrierCallbackForPut* barrier_callback,
+ BarrierCallbackForPutComplete* barrier_callback,
Request* request,
Response* response,
+ scoped_refptr<BlobDataHandle> blob_handle,
int64_t trace_id)
: script_state_(script_state),
index_(index),
barrier_callback_(barrier_callback),
mime_type_(response->InternalMIMEType()),
+ blob_handle_(std::move(blob_handle)),
trace_id_(trace_id) {
fetch_api_request_ = request->CreateFetchAPIRequest();
fetch_api_response_ = response->PopulateFetchAPIResponse(request->url());
@@ -460,13 +659,7 @@ class Cache::CodeCacheHandleCallbackForPut final
batch_operation->operation_type = mojom::blink::OperationType::kPut;
batch_operation->request = std::move(fetch_api_request_);
batch_operation->response = std::move(fetch_api_response_);
-
- auto blob_data = std::make_unique<BlobData>();
- blob_data->SetContentType(mime_type_);
- blob_data->AppendBytes(array_buffer->Data(),
- array_buffer->ByteLengthAsSizeT());
- batch_operation->response->blob = BlobDataHandle::Create(
- std::move(blob_data), array_buffer->ByteLengthAsSizeT());
+ batch_operation->response->blob = std::move(blob_handle_);
scoped_refptr<CachedMetadata> cached_metadata =
GenerateFullCodeCache(array_buffer);
@@ -532,8 +725,9 @@ class Cache::CodeCacheHandleCallbackForPut final
const Member<ScriptState> script_state_;
const wtf_size_t index_;
- Member<BarrierCallbackForPut> barrier_callback_;
+ Member<BarrierCallbackForPutComplete> barrier_callback_;
const String mime_type_;
+ scoped_refptr<BlobDataHandle> blob_handle_;
KURL url_;
V8CodeCache::OpaqueMode opaque_mode_;
const int64_t trace_id_;
@@ -625,26 +819,38 @@ ScriptPromise Cache::Delete(ScriptState* script_state,
}
ScriptPromise Cache::put(ScriptState* script_state,
- const RequestInfo& request,
+ const RequestInfo& request_info,
Response* response,
ExceptionState& exception_state) {
- DCHECK(!request.IsNull());
+ DCHECK(!request_info.IsNull());
int64_t trace_id = blink::cache_storage::CreateTraceId();
TRACE_EVENT_WITH_FLOW0("CacheStorage", "Cache::put",
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
- if (request.IsRequest()) {
- return PutImpl(script_state, "Cache.put()",
- HeapVector<Member<Request>>(1, request.GetAsRequest()),
- HeapVector<Member<Response>>(1, response), exception_state,
- trace_id);
- }
- Request* new_request =
- Request::Create(script_state, request.GetAsUSVString(), exception_state);
+ Request* request =
+ request_info.IsRequest()
+ ? request_info.GetAsRequest()
+ : Request::Create(script_state, request_info.GetAsUSVString(),
+ exception_state);
+ if (exception_state.HadException())
+ return ScriptPromise();
+
+ ValidateRequestForPut(request, exception_state);
if (exception_state.HadException())
return ScriptPromise();
- return PutImpl(
- script_state, "Cache.put()", HeapVector<Member<Request>>(1, new_request),
- HeapVector<Member<Response>>(1, response), exception_state, trace_id);
+
+ auto* barrier_callback = MakeGarbageCollected<BarrierCallbackForPutResponse>(
+ script_state, this, "Cache.put()",
+ HeapVector<Member<Request>>(1, request), exception_state, trace_id);
+
+ // We must get the promise before any rejections can happen during loading.
+ ScriptPromise promise = barrier_callback->Promise();
+
+ auto* loader = MakeGarbageCollected<ResponseBodyLoader>(
+ script_state, barrier_callback, /*index=*/0,
+ /*require_ok_response=*/false, trace_id);
+ loader->OnResponse(response, exception_state);
+
+ return promise;
}
ScriptPromise Cache::keys(ScriptState* script_state, ExceptionState&) {
@@ -680,6 +886,10 @@ void Cache::Trace(Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
}
+AbortController* Cache::CreateAbortController(ExecutionContext* context) {
+ return AbortController::Create(context);
+}
+
ScriptPromise Cache::MatchImpl(ScriptState* script_state,
const Request* request,
const CacheQueryOptions* options) {
@@ -843,40 +1053,49 @@ ScriptPromise Cache::MatchAllImpl(ScriptState* script_state,
ScriptPromise Cache::AddAllImpl(ScriptState* script_state,
const String& method_name,
- const HeapVector<Member<Request>>& requests,
+ const HeapVector<Member<Request>>& request_list,
ExceptionState& exception_state) {
int64_t trace_id = blink::cache_storage::CreateTraceId();
TRACE_EVENT_WITH_FLOW0("CacheStorage", "Cache::AddAllImpl",
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
- if (requests.IsEmpty())
+ if (request_list.IsEmpty())
return ScriptPromise::CastUndefined(script_state);
- HeapVector<RequestInfo> request_infos;
- request_infos.resize(requests.size());
- HeapVector<ScriptPromise> promises;
- promises.resize(requests.size());
- for (wtf_size_t i = 0; i < requests.size(); ++i) {
- if (!requests[i]->url().ProtocolIsInHTTPFamily()) {
- exception_state.ThrowTypeError(
- "Add/AddAll does not support schemes "
- "other than \"http\" or \"https\"");
- return ScriptPromise();
- }
- if (requests[i]->method() != http_names::kGET) {
- exception_state.ThrowTypeError(
- "Add/AddAll only supports the GET request method.");
+ // Validate all requests before starting to load or store any of them.
+ for (wtf_size_t i = 0; i < request_list.size(); ++i) {
+ ValidateRequestForPut(request_list[i], exception_state);
+ if (exception_state.HadException())
return ScriptPromise();
- }
- request_infos[i].SetRequest(requests[i]);
+ }
- promises[i] = scoped_fetcher_->Fetch(
- script_state, request_infos[i], RequestInit::Create(), exception_state);
+ auto* barrier_callback = MakeGarbageCollected<BarrierCallbackForPutResponse>(
+ script_state, this, method_name, request_list, exception_state, trace_id);
+
+ // We must get the promise before any rejections can happen during loading.
+ ScriptPromise promise = barrier_callback->Promise();
+
+ // Begin loading each of the requests.
+ for (wtf_size_t i = 0; i < request_list.size(); ++i) {
+ // Chain the AbortSignal objects together so the requests will abort if
+ // the |barrier_callback| encounters an error.
+ request_list[i]->signal()->Follow(barrier_callback->Signal());
+
+ RequestInfo info;
+ info.SetRequest(request_list[i]);
+
+ auto* response_loader = MakeGarbageCollected<ResponseBodyLoader>(
+ script_state, barrier_callback, i, /*require_ok_response=*/true,
+ trace_id);
+ scoped_fetcher_
+ ->Fetch(script_state, info, RequestInit::Create(), exception_state)
+ .Then(FetchHandler::CreateForResolve(script_state, response_loader,
+ barrier_callback, exception_state),
+ FetchHandler::CreateForReject(script_state, barrier_callback,
+ exception_state));
}
- return ScriptPromise::All(script_state, promises)
- .Then(FetchResolvedForAdd::Create(script_state, this, method_name,
- requests, exception_state, trace_id));
+ return promise;
}
ScriptPromise Cache::DeleteImpl(ScriptState* script_state,
@@ -947,91 +1166,57 @@ ScriptPromise Cache::DeleteImpl(ScriptState* script_state,
return promise;
}
-ScriptPromise Cache::PutImpl(ScriptState* script_state,
- const String& method_name,
- const HeapVector<Member<Request>>& requests,
- const HeapVector<Member<Response>>& responses,
- ExceptionState& exception_state,
- int64_t trace_id) {
+void Cache::PutImpl(ScriptPromiseResolver* resolver,
+ const String& method_name,
+ const HeapVector<Member<Request>>& requests,
+ const HeapVector<Member<Response>>& responses,
+ const WTF::Vector<scoped_refptr<BlobDataHandle>>& blob_list,
+ ExceptionState& exception_state,
+ int64_t trace_id) {
+ DCHECK_EQ(requests.size(), responses.size());
+ DCHECK_EQ(requests.size(), blob_list.size());
+
TRACE_EVENT_WITH_FLOW0("CacheStorage", "Cache::PutImpl",
TRACE_ID_GLOBAL(trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- const ScriptPromise promise = resolver->Promise();
- BarrierCallbackForPut* barrier_callback =
- MakeGarbageCollected<BarrierCallbackForPut>(
- requests.size(), this, method_name, resolver, trace_id);
- for (wtf_size_t i = 0; i < requests.size(); ++i) {
- KURL url(NullURL(), requests[i]->url());
- if (!url.ProtocolIsInHTTPFamily()) {
- barrier_callback->OnError("Request scheme '" + url.Protocol() +
- "' is unsupported");
- return promise;
- }
- if (requests[i]->method() != http_names::kGET) {
- barrier_callback->OnError("Request method '" + requests[i]->method() +
- "' is unsupported");
- return promise;
- }
- DCHECK(!requests[i]->HasBody());
+ ScriptState* script_state = resolver->GetScriptState();
+ ScriptState::Scope scope(script_state);
+ ExecutionContext* context = ExecutionContext::From(script_state);
- if (VaryHeaderContainsAsterisk(responses[i])) {
- barrier_callback->OnError("Vary header contains *");
- return promise;
- }
- if (responses[i]->status() == 206) {
- barrier_callback->OnError(
- "Partial response (status code 206) is unsupported");
- return promise;
- }
- if (responses[i]->IsBodyLocked() || responses[i]->IsBodyUsed()) {
- barrier_callback->OnError("Response body is already used");
- return promise;
- }
+ BarrierCallbackForPutComplete* barrier_callback =
+ MakeGarbageCollected<BarrierCallbackForPutComplete>(
+ requests.size(), this, method_name, resolver, trace_id);
- BodyStreamBuffer* buffer = responses[i]->InternalBodyBuffer();
-
- if (ShouldGenerateV8CodeCache(script_state, responses[i])) {
- FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsArrayBuffer();
- buffer->StartLoading(loader,
- MakeGarbageCollected<CodeCacheHandleCallbackForPut>(
- script_state, i, barrier_callback, requests[i],
- responses[i], trace_id),
- exception_state);
- if (exception_state.HadException()) {
- barrier_callback->OnError("Could not inspect response body state");
- return promise;
- }
+ for (wtf_size_t i = 0; i < requests.size(); ++i) {
+ if (!blob_list[i] ||
+ !ShouldGenerateV8CodeCache(script_state, responses[i])) {
+ mojom::blink::BatchOperationPtr batch_operation =
+ mojom::blink::BatchOperation::New();
+ batch_operation->operation_type = mojom::blink::OperationType::kPut;
+ batch_operation->request = requests[i]->CreateFetchAPIRequest();
+ batch_operation->response =
+ responses[i]->PopulateFetchAPIResponse(requests[i]->url());
+ batch_operation->response->blob = std::move(blob_list[i]);
+ barrier_callback->OnSuccess(i, std::move(batch_operation));
continue;
}
- if (buffer) {
- // If the response has body, read the all data and create
- // the blob handle and dispatch the put batch asynchronously.
- FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsBlobHandle(
- responses[i]->InternalMIMEType());
- buffer->StartLoading(loader,
- MakeGarbageCollected<BlobHandleCallbackForPut>(
- i, barrier_callback, requests[i], responses[i]),
- exception_state);
- if (exception_state.HadException()) {
- barrier_callback->OnError("Could not inspect response body state");
- return promise;
- }
- continue;
+ BytesConsumer* consumer =
+ MakeGarbageCollected<BlobBytesConsumer>(context, blob_list[i]);
+ BodyStreamBuffer* buffer =
+ BodyStreamBuffer::Create(script_state, consumer, /*signal=*/nullptr);
+ FetchDataLoader* loader = FetchDataLoader::CreateLoaderAsArrayBuffer();
+ buffer->StartLoading(loader,
+ MakeGarbageCollected<CodeCacheHandleCallbackForPut>(
+ script_state, i, barrier_callback, requests[i],
+ responses[i], std::move(blob_list[i]), trace_id),
+ exception_state);
+ if (exception_state.HadException()) {
+ barrier_callback->OnError("Could not inspect response body state");
+ return;
}
-
- mojom::blink::BatchOperationPtr batch_operation =
- mojom::blink::BatchOperation::New();
- batch_operation->operation_type = mojom::blink::OperationType::kPut;
- batch_operation->request = requests[i]->CreateFetchAPIRequest();
- batch_operation->response =
- responses[i]->PopulateFetchAPIResponse(requests[i]->url());
- barrier_callback->OnSuccess(i, std::move(batch_operation));
}
-
- return promise;
}
ScriptPromise Cache::KeysImpl(ScriptState* script_state,
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 4e8439fa1bc..74f36eda42e 100644
--- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
+++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.h
@@ -40,15 +40,17 @@ struct TypeConverter<CacheQueryOptionsPtr, const blink::CacheQueryOptions*> {
namespace blink {
+class AbortController;
class CacheStorageBlobClientList;
class ExceptionState;
class Response;
class Request;
+class ScriptPromiseResolver;
class ScriptState;
typedef RequestOrUSVString RequestInfo;
-class MODULES_EXPORT Cache final : public ScriptWrappable {
+class MODULES_EXPORT Cache : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -86,12 +88,16 @@ class MODULES_EXPORT Cache final : public ScriptWrappable {
void Trace(Visitor*) const override;
+ protected:
+ // Virtual for testing.
+ virtual AbortController* CreateAbortController(ExecutionContext* context);
+
private:
- class BarrierCallbackForPut;
- class BlobHandleCallbackForPut;
+ class BarrierCallbackForPutResponse;
+ class BarrierCallbackForPutComplete;
class CodeCacheHandleCallbackForPut;
- class FetchResolvedForAdd;
- friend class FetchResolvedForAdd;
+ class ResponseBodyLoader;
+ class FetchHandler;
ScriptPromise MatchImpl(ScriptState*,
const Request*,
@@ -106,12 +112,13 @@ class MODULES_EXPORT Cache final : public ScriptWrappable {
ScriptPromise DeleteImpl(ScriptState*,
const Request*,
const CacheQueryOptions*);
- ScriptPromise PutImpl(ScriptState*,
- const String& method_name,
- const HeapVector<Member<Request>>&,
- const HeapVector<Member<Response>>&,
- ExceptionState&,
- int64_t trace_id);
+ void PutImpl(ScriptPromiseResolver*,
+ const String& method_name,
+ const HeapVector<Member<Request>>&,
+ const HeapVector<Member<Response>>&,
+ const WTF::Vector<scoped_refptr<BlobDataHandle>>& blob_list,
+ ExceptionState&,
+ int64_t trace_id);
ScriptPromise KeysImpl(ScriptState*,
const Request*,
const CacheQueryOptions*);
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 e2665709efb..432a40115db 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
@@ -76,7 +76,10 @@ bool IsCacheStorageAllowed(ScriptState* script_state) {
settings_client = To<WorkerGlobalScope>(context)->ContentSettingsClient();
// This triggers a sync IPC.
- return settings_client ? settings_client->AllowCacheStorage() : true;
+ return settings_client
+ ? settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kCacheStorage)
+ : true;
}
} // namespace
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 ad61fb621e3..1a3b3a6d5c1 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
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_request_init.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_response.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_response_init.h"
+#include "third_party/blink/renderer/core/dom/abort_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/fetch/body_stream_buffer.h"
@@ -55,7 +56,7 @@ class ScopedFetcherForTests final
: public GarbageCollected<ScopedFetcherForTests>,
public GlobalFetch::ScopedFetcher {
public:
- ScopedFetcherForTests() : fetch_count_(0), expected_url_(nullptr) {}
+ ScopedFetcherForTests() = default;
ScriptPromise Fetch(ScriptState* script_state,
const RequestInfo& request_info,
@@ -90,7 +91,7 @@ class ScopedFetcherForTests final
}
void SetResponse(Response* response) { response_ = response; }
- int FetchCount() const { return fetch_count_; }
+ uint32_t FetchCount() const override { return fetch_count_; }
void Trace(Visitor* visitor) const override {
visitor->Trace(response_);
@@ -98,8 +99,8 @@ class ScopedFetcherForTests final
}
private:
- int fetch_count_;
- const String* expected_url_;
+ uint32_t fetch_count_ = 0;
+ const String* expected_url_ = nullptr;
Member<Response> response_;
};
@@ -257,19 +258,46 @@ class NotImplementedErrorCache : public ErrorCacheForTests {
mojom::blink::CacheStorageError::kErrorNotImplemented) {}
};
+class TestCache : public Cache {
+ public:
+ TestCache(
+ GlobalFetch::ScopedFetcher* fetcher,
+ mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> remote,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : Cache(fetcher, std::move(remote), std::move(task_runner)) {}
+
+ bool IsAborted() const {
+ return abort_controller_ && abort_controller_->signal()->aborted();
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(abort_controller_);
+ Cache::Trace(visitor);
+ }
+
+ protected:
+ AbortController* CreateAbortController(ExecutionContext* context) override {
+ if (!abort_controller_)
+ abort_controller_ = AbortController::Create(context);
+ return abort_controller_;
+ }
+
+ private:
+ Member<blink::AbortController> abort_controller_;
+};
+
class CacheStorageTest : public PageTestBase {
public:
void SetUp() override { PageTestBase::SetUp(IntSize(1, 1)); }
- Cache* CreateCache(ScopedFetcherForTests* fetcher,
- std::unique_ptr<ErrorCacheForTests> cache) {
+ TestCache* CreateCache(ScopedFetcherForTests* fetcher,
+ std::unique_ptr<ErrorCacheForTests> cache) {
mojo::AssociatedRemote<mojom::blink::CacheStorageCache> cache_remote;
cache_ = std::move(cache);
receiver_ = std::make_unique<
mojo::AssociatedReceiver<mojom::blink::CacheStorageCache>>(
- cache_.get(),
- cache_remote.BindNewEndpointAndPassDedicatedReceiverForTesting());
- return MakeGarbageCollected<Cache>(
+ cache_.get(), cache_remote.BindNewEndpointAndPassDedicatedReceiver());
+ return MakeGarbageCollected<TestCache>(
fetcher, cache_remote.Unbind(),
blink::scheduler::GetSingleThreadTaskRunnerForTesting());
}
@@ -750,11 +778,40 @@ TEST_F(CacheStorageTest, Add) {
GetScriptState(), RequestToRequestInfo(request), exception_state);
EXPECT_EQ(kNotImplementedString, GetRejectString(add_result));
- EXPECT_EQ(1, fetcher->FetchCount());
+ EXPECT_EQ(1u, fetcher->FetchCount());
EXPECT_EQ("dispatchBatch",
test_cache()->GetAndClearLastErrorWebCacheMethodCalled());
}
+// Verify an error response causes Cache::addAll() to trigger its associated
+// AbortController to cancel outstanding requests.
+TEST_F(CacheStorageTest, AddAllAbort) {
+ ScriptState::Scope scope(GetScriptState());
+ DummyExceptionStateForTesting exception_state;
+ auto* fetcher = MakeGarbageCollected<ScopedFetcherForTests>();
+ const String url = "http://www.cacheadd.test/";
+ const String content_type = "text/plain";
+ const String content = "hello cache";
+
+ TestCache* cache =
+ CreateCache(fetcher, std::make_unique<NotImplementedErrorCache>());
+
+ Request* request = NewRequestFromUrl(url);
+ fetcher->SetExpectedFetchUrl(&url);
+
+ Response* response = Response::error(GetScriptState());
+ fetcher->SetResponse(response);
+
+ HeapVector<RequestInfo> info_list;
+ info_list.push_back(RequestToRequestInfo(request));
+
+ ScriptPromise promise =
+ cache->addAll(GetScriptState(), info_list, exception_state);
+
+ EXPECT_EQ("TypeError: Request failed", GetRejectString(promise));
+ EXPECT_TRUE(cache->IsAborted());
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
index dcbce9e0e00..3dee2798eee 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn
@@ -48,6 +48,12 @@ fuzzer_test("canvas_fuzzer") {
seed_corpuses = [ "//third_party/blink/web_tests/fast/canvas" ]
deps = [
"../../platform:blink_fuzzer_test_support",
+ "//base/test:test_support",
"//third_party/blink/renderer/core",
+ "//third_party/blink/renderer/core:testing",
+ "//third_party/blink/renderer/platform:test_support",
]
+
+ # Disabled due to many false positives (crbug.com/1124824).
+ additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
}
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 45a4034ad78..4c512aea8da 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
@@ -138,7 +138,7 @@ void BaseRenderingContext2D::UnwindStateStack() {
}
}
-void BaseRenderingContext2D::Reset() {
+void BaseRenderingContext2D::reset() {
ValidateStateStack();
UnwindStateStack();
state_stack_.resize(1);
@@ -985,17 +985,16 @@ static inline CanvasImageSource* ToImageSourceInternal(
.IsEmpty()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
- String::Format("The image argument is a canvas element with a width "
- "or height of 0."));
+ "The image argument is a canvas element with a width "
+ "or height of 0.");
return nullptr;
}
return value.GetAsHTMLCanvasElement();
}
if (value.IsImageBitmap()) {
if (static_cast<ImageBitmap*>(value.GetAsImageBitmap())->IsNeutered()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- String::Format("The image source is detached"));
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The image source is detached");
return nullptr;
}
return value.GetAsImageBitmap();
@@ -1003,9 +1002,8 @@ static inline CanvasImageSource* ToImageSourceInternal(
if (value.IsOffscreenCanvas()) {
if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
->IsNeutered()) {
- exception_state.ThrowDOMException(
- DOMExceptionCode::kInvalidStateError,
- String::Format("The image source is detached"));
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The image source is detached");
return nullptr;
}
if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas())
@@ -1013,8 +1011,8 @@ static inline CanvasImageSource* ToImageSourceInternal(
.IsEmpty()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
- String::Format("The image argument is an OffscreenCanvas element "
- "with a width or height of 0."));
+ "The image argument is an OffscreenCanvas element "
+ "with a width or height of 0.");
return nullptr;
}
return value.GetAsOffscreenCanvas();
@@ -1578,26 +1576,6 @@ ImageData* BaseRenderingContext2D::createImageData(
exception_state);
}
-ImageData* BaseRenderingContext2D::createImageData(
- ImageDataArray& data_array,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) const {
- return ImageData::CreateImageData(data_array, width, height,
- ImageDataColorSettings::Create(),
- exception_state);
-}
-
-ImageData* BaseRenderingContext2D::createImageData(
- ImageDataArray& data_array,
- unsigned width,
- unsigned height,
- ImageDataColorSettings* color_settings,
- ExceptionState& exception_state) const {
- return ImageData::CreateImageData(data_array, width, height, color_settings,
- exception_state);
-}
-
ImageData* BaseRenderingContext2D::getImageData(
int sx,
int sy,
@@ -1851,8 +1829,11 @@ void BaseRenderingContext2D::putImageData(ImageData* data,
IntPoint(dest_offset));
}
} else {
- PutByteArray(data->data()->Data(), IntSize(data->width(), data->height()),
- source_rect, IntPoint(dest_offset));
+ // TODO(crbug.com/1115317): PutByteArray works with uint8 only. It should be
+ // compatible with uint16 and float32.
+ PutByteArray(data->data().GetAsUint8ClampedArray()->Data(),
+ IntSize(data->width(), data->height()), source_rect,
+ IntPoint(dest_offset));
}
if (!IsPaint2D()) {
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 a0ce8e4948f..f7fc03fa507 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
@@ -32,8 +32,6 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
public:
~BaseRenderingContext2D() override;
- void Reset();
-
void strokeStyle(StringOrCanvasGradientOrCanvasPattern&) const;
void setStrokeStyle(const StringOrCanvasGradientOrCanvasPattern&);
@@ -81,6 +79,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
void save();
void restore();
+ void reset();
void scale(double sx, double sy);
void rotate(double angle_in_radians);
@@ -188,15 +187,6 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
unsigned,
ImageDataColorSettings*,
ExceptionState&) const;
- ImageData* createImageData(ImageDataArray&,
- unsigned,
- unsigned,
- ExceptionState&) const;
- ImageData* createImageData(ImageDataArray&,
- unsigned,
- unsigned,
- ImageDataColorSettings*,
- ExceptionState&) const;
// For deferred canvases this will have the side effect of drawing recorded
// commands in order to finalize the frame
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 772c8b221c9..ca1ac8b252c 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
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h"
#include "base/numerics/safe_conversions.h"
+#include "third_party/blink/renderer/core/geometry/dom_point.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
@@ -448,4 +449,60 @@ void CanvasPath::rect(double double_x,
path_.AddRect(FloatRect(x, y, width, height));
}
+
+void CanvasPath::roundRect(double double_x,
+ double double_y,
+ double double_width,
+ double double_height,
+ const HeapVector<DoubleOrDOMPoint, 0> radii,
+ ExceptionState& exception_state) {
+ const int num_radii = radii.size();
+ if (num_radii < 1 || num_radii > 4) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ String::Number(num_radii) +
+ " radii provided. Between one and four radii are necessary.");
+ }
+
+ float x = base::saturated_cast<float>(double_x);
+ float y = base::saturated_cast<float>(double_y);
+ float width = base::saturated_cast<float>(double_width);
+ float height = base::saturated_cast<float>(double_height);
+ if (!IsTransformInvertible())
+ return;
+
+ if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) ||
+ !std::isfinite(height))
+ return;
+
+ FloatRect rect = FloatRect(x, y, width, height);
+
+ FloatSize r[num_radii];
+ for (int i = 0; i < num_radii; ++i) {
+ if (radii[i].IsDouble()) {
+ float a = base::saturated_cast<float>(radii[i].GetAsDouble());
+ r[i] = FloatSize(a, a);
+ } else { // This radius is a DOMPoint
+ DOMPoint* p = radii[i].GetAsDOMPoint();
+ r[i] = FloatSize(base::saturated_cast<float>(p->x()),
+ base::saturated_cast<float>(p->y()));
+ }
+ }
+
+ // Order of arguments here is so that this function behaves the same as the
+ // CSS border-radius property
+ switch (num_radii) {
+ case 1:
+ path_.AddRoundedRect(rect, r[0]);
+ break;
+ case 2:
+ path_.AddRoundedRect(rect, r[0], r[1], r[1], r[0]);
+ break;
+ case 3:
+ path_.AddRoundedRect(rect, r[0], r[1], r[1], r[2]);
+ break;
+ case 4:
+ path_.AddRoundedRect(rect, r[0], r[1], r[3], r[2]);
+ }
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
index 27fb15f451f..4e1040c0026 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
@@ -30,6 +30,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_PATH_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_PATH_H_
+#include "third_party/blink/renderer/bindings/modules/v8/double_or_dom_point.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
@@ -84,6 +85,12 @@ class MODULES_EXPORT CanvasPath {
double double_y,
double double_width,
double double_height);
+ void roundRect(double double_x,
+ double double_y,
+ double double_width,
+ double double_height,
+ const HeapVector<DoubleOrDOMPoint, 0> radii,
+ ExceptionState&);
virtual bool IsTransformInvertible() const { return true; }
virtual AffineTransform Transform() const {
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 0317df56871..299c4b1e656 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
@@ -13,6 +13,8 @@ interface mixin CanvasPath {
void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y);
[RaisesException] void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius);
void rect(unrestricted double x, unrestricted double y, unrestricted double width, unrestricted double height);
+ [RuntimeEnabled=NewCanvas2DAPI, RaisesException] void roundRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h, sequence<(double or DOMPoint)> radii);
+
[RaisesException] void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
[RaisesException] void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
};
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 2f35115caa5..cca2abb108c 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
@@ -38,6 +38,8 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/modules/v8/rendering_context.h"
@@ -321,7 +323,7 @@ CanvasPixelFormat CanvasRenderingContext2D::PixelFormat() const {
void CanvasRenderingContext2D::Reset() {
// This is a multiple inheritance bootstrap
- BaseRenderingContext2D::Reset();
+ BaseRenderingContext2D::reset();
}
void CanvasRenderingContext2D::RestoreCanvasMatrixClipStack(
@@ -680,12 +682,13 @@ ImageData* CanvasRenderingContext2D::getImageData(
int sw,
int sh,
ExceptionState& exception_state) {
- blink::IdentifiabilityMetricBuilder(ukm_source_id_)
- .Set(blink::IdentifiableSurface::FromTypeAndInput(
- blink::IdentifiableSurface::Type::kCanvasReadback,
- GetContextType()),
- 0)
- .Record(ukm_recorder_);
+ const IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kCanvasReadback, GetContextType());
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
+ blink::IdentifiabilityMetricBuilder(ukm_source_id_)
+ .Set(surface, 0)
+ .Record(ukm_recorder_);
+ }
return BaseRenderingContext2D::getImageData(sx, sy, sw, sh, exception_state);
}
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 9d47e14250a..9a27c3af043 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
@@ -52,6 +52,8 @@ interface CanvasRenderingContext2D {
// state
void save(); // push state on state stack
void restore(); // pop state stack and restore state
+ // Clear the canvas and reset the path
+ [RuntimeEnabled=NewCanvas2DAPI] void reset();
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
@@ -133,7 +135,6 @@ interface CanvasRenderingContext2D {
// https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md
[RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(unsigned long sw, unsigned long sh, ImageDataColorSettings imageDataColorSettings);
- [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(ImageDataArray data, unsigned long sw, unsigned long sh, optional ImageDataColorSettings imageDataColorSettings = {});
// Context state
// Should be merged with WebGL counterpart in CanvasRenderingContext, once no-longer experimental
@@ -158,7 +159,6 @@ interface CanvasRenderingContext2D {
attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
attribute DOMString direction; // "inherit", "rtl", "ltr" (default: "inherit")
-
};
CanvasRenderingContext2D includes CanvasPath;
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
index 99185a319f5..ead1d044954 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
@@ -235,10 +235,12 @@ TEST_F(CanvasRenderingContext2DAPITest, CreateImageData) {
EXPECT_EQ(100, image_data->width());
EXPECT_EQ(50, image_data->height());
- for (size_t i = 0; i < image_data->data()->lengthAsSizeT(); ++i)
- image_data->data()->Data()[i] = 255;
+ for (size_t i = 0;
+ i < image_data->data().GetAsUint8ClampedArray()->lengthAsSizeT(); ++i) {
+ image_data->data().GetAsUint8ClampedArray()->Data()[i] = 255;
+ }
- EXPECT_EQ(255, image_data->data()->Data()[32]);
+ EXPECT_EQ(255, image_data->data().GetAsUint8ClampedArray()->Data()[32]);
// createImageData(imageData) should create a new ImageData of the same size
// as 'imageData' but filled with transparent black
@@ -248,7 +250,8 @@ TEST_F(CanvasRenderingContext2DAPITest, CreateImageData) {
EXPECT_FALSE(exception_state.HadException());
EXPECT_EQ(100, same_size_image_data->width());
EXPECT_EQ(50, same_size_image_data->height());
- EXPECT_EQ(0, same_size_image_data->data()->Data()[32]);
+ EXPECT_EQ(0,
+ same_size_image_data->data().GetAsUint8ClampedArray()->Data()[32]);
// createImageData(width, height) takes the absolute magnitude of the size
// arguments
@@ -262,10 +265,10 @@ TEST_F(CanvasRenderingContext2DAPITest, CreateImageData) {
ImageData* imgdata4 = Context2D()->createImageData(-10, -20, exception_state);
EXPECT_FALSE(exception_state.HadException());
- EXPECT_EQ(800u, imgdata1->data()->lengthAsSizeT());
- EXPECT_EQ(800u, imgdata2->data()->lengthAsSizeT());
- EXPECT_EQ(800u, imgdata3->data()->lengthAsSizeT());
- EXPECT_EQ(800u, imgdata4->data()->lengthAsSizeT());
+ EXPECT_EQ(800u, imgdata1->data().GetAsUint8ClampedArray()->lengthAsSizeT());
+ EXPECT_EQ(800u, imgdata2->data().GetAsUint8ClampedArray()->lengthAsSizeT());
+ EXPECT_EQ(800u, imgdata3->data().GetAsUint8ClampedArray()->lengthAsSizeT());
+ EXPECT_EQ(800u, imgdata4->data().GetAsUint8ClampedArray()->lengthAsSizeT());
}
TEST_F(CanvasRenderingContext2DAPITest, CreateImageDataTooBig) {
@@ -383,15 +386,15 @@ TEST_F(CanvasRenderingContext2DAPITest,
class ActiveSettingsProvider : public IdentifiabilityStudySettingsProvider {
public:
bool IsActive() const override { return true; }
-
- // The following return values don't matter.
- bool IsAnyTypeOrSurfaceBlocked() const override { return true; }
+ bool IsAnyTypeOrSurfaceBlocked() const override { return false; }
bool IsSurfaceAllowed(IdentifiableSurface surface) const override {
- return false;
+ return true;
}
bool IsTypeAllowed(IdentifiableSurface::Type type) const override {
- return false;
+ return true;
}
+ int SampleRate(IdentifiableSurface surface) const override { return 1; }
+ int SampleRate(IdentifiableSurface::Type type) const override { return 1; }
};
// An RAII class that opts into study participation using
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 316014a4c06..d4ded1c9a9c 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
@@ -125,11 +125,8 @@ void CanvasRenderingContext2DState::FontsNeedUpdate(FontSelector* font_selector,
DCHECK_EQ(font_selector, font_.GetFontSelector());
DCHECK(realized_font_);
- if (!RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) {
- // With the feature enabled, |font_| will revalidate its FontFallbackList on
- // demand. We don't need to manually reset the Font object here.
- font_ = Font(font_.GetFontDescription(), font_selector);
- }
+ // |font_| will revalidate its FontFallbackList on demand. We don't need to
+ // manually reset the Font object here.
// FIXME: We only really need to invalidate the resolved filter if the font
// update above changed anything and the filter uses font-dependent units.
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 17bba252101..0c0d58c65d1 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
@@ -784,7 +784,7 @@ static void TestDrawSingleHighBitDepthPNGOnCanvas(
context->drawImage(script_state, image_union, 0, 0, exception_state);
ImageData* image_data = context->getImageData(0, 0, 2, 2, exception_state);
- ImageDataArray data_array = image_data->dataUnion();
+ ImageDataArray data_array = image_data->data();
ASSERT_TRUE(data_array.IsFloat32Array());
DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().View();
ASSERT_EQ(16u, buffer_view->byteLengthAsSizeT() / buffer_view->TypeSize());
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 9c728290626..89c1c49c10d 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
@@ -52,7 +52,7 @@ enum ColorParseResult {
static ColorParseResult ParseColor(Color& parsed_color,
const String& color_string,
- WebColorScheme color_scheme) {
+ ColorScheme color_scheme) {
if (EqualIgnoringASCIICase(color_string, "currentcolor"))
return kParsedCurrentColor;
const bool kUseStrictParsing = true;
@@ -72,7 +72,7 @@ static Color CurrentColor(HTMLCanvasElement* canvas) {
return color;
}
-static WebColorScheme ColorScheme(HTMLCanvasElement* canvas) {
+static ColorScheme ColorScheme(HTMLCanvasElement* canvas) {
if (canvas && canvas->isConnected()) {
if (auto* style = canvas->GetComputedStyle())
return style->UsedColorScheme();
diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
index 8efefb71b45..c45827a2850 100644
--- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
+++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
-#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
@@ -51,8 +51,10 @@ class IdentifiabilityStudyHelper {
public:
template <typename... Ts>
void MaybeUpdateBuilder(Ts... tokens) {
- if (!IsUserInIdentifiabilityStudy())
+ if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+ blink::IdentifiableSurface::Type::kCanvasReadback)) {
return;
+ }
if (operation_count_ >= max_operations_) {
encountered_skipped_ops_ = true;
return;
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 9f5dd81892c..dfd453b6d88 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
@@ -87,10 +87,8 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(
is_valid_size_ = IsValidImageSize(Host()->Size());
// Clear the background transparent or opaque.
- if (IsCanvas2DBufferValid()) {
- GetCanvasResourceProvider()->Clear();
+ if (IsCanvas2DBufferValid())
DidDraw();
- }
ExecutionContext* execution_context = canvas->GetTopExecutionContext();
if (auto* window = DynamicTo<LocalDOMWindow>(execution_context)) {
@@ -179,7 +177,7 @@ OffscreenCanvasRenderingContext2D::GetCanvasResourceProvider() const {
}
void OffscreenCanvasRenderingContext2D::Reset() {
Host()->DiscardResourceProvider();
- BaseRenderingContext2D::Reset();
+ BaseRenderingContext2D::reset();
// Because the host may have changed to a zero size
is_valid_size_ = IsValidImageSize(Host()->Size());
}
@@ -220,17 +218,10 @@ ImageBitmap* OffscreenCanvasRenderingContext2D::TransferToImageBitmap(
if (!image)
return nullptr;
image->SetOriginClean(this->OriginClean());
- if (image->IsTextureBacked()) {
- // Before discarding the image resource, we need to flush pending render ops
- // to fully resolve the snapshot.
- // We can only do this if the skImage is not null
- if (auto skImage = image->PaintImageForCurrentFrame().GetSkImage()) {
- skImage->getBackendTexture(true); // Flush pending ops.
- } else {
- // If the SkImage was null, we better return a null ImageBitmap
- return nullptr;
- }
- }
+ // Before discarding the image resource, we need to flush pending render ops
+ // to fully resolve the snapshot.
+ image->PaintImageForCurrentFrame().FlushPendingSkiaOps();
+
Host()->DiscardResourceProvider();
return MakeGarbageCollected<ImageBitmap>(std::move(image));
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 a58003a655e..ae62768191e 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
@@ -16,6 +16,8 @@
// state
void save(); // push state on state stack
void restore(); // pop state stack and restore state
+ // Clear the canvas and reset the path
+ [RuntimeEnabled=NewCanvas2DAPI] void reset();
// transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y);
@@ -88,8 +90,6 @@
// If OffscreenCanva ships before color managed canvas, this method must remain behind flag.
// https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md
[RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(unsigned long sw, unsigned long sh, ImageDataColorSettings imageDataColorSettings);
- [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(ImageDataArray data, unsigned long sw, unsigned long sh, ImageDataColorSettings imageDataColorSettings);
-
// Line caps/joins
attribute unrestricted double lineWidth; // (default 1)
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc
index a28299efad4..e7abcdbbe82 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_reader.cc
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -45,14 +46,14 @@ class ClipboardImageReader final : public ClipboardReader {
}
worker_pool::PostTask(
- FROM_HERE, CrossThreadBindOnce(
- &ClipboardImageReader::EncodeImageOnBackgroundThread,
- std::move(image), WrapCrossThreadPersistent(this),
- std::move(clipboard_task_runner_)));
+ FROM_HERE,
+ CrossThreadBindOnce(&ClipboardImageReader::EncodeOnBackgroundThread,
+ std::move(image), WrapCrossThreadPersistent(this),
+ std::move(clipboard_task_runner_)));
}
private:
- static void EncodeImageOnBackgroundThread(
+ static void EncodeOnBackgroundThread(
sk_sp<SkImage> image,
ClipboardImageReader* reader,
scoped_refptr<base::SingleThreadTaskRunner> clipboard_task_runner) {
@@ -110,13 +111,13 @@ class ClipboardTextReader final : public ClipboardReader {
worker_pool::PostTask(
FROM_HERE, CrossThreadBindOnce(
- &ClipboardTextReader::EncodeTextOnBackgroundThread,
+ &ClipboardTextReader::EncodeOnBackgroundThread,
std::move(plain_text), WrapCrossThreadPersistent(this),
std::move(clipboard_task_runner_)));
}
private:
- static void EncodeTextOnBackgroundThread(
+ static void EncodeOnBackgroundThread(
String plain_text,
ClipboardTextReader* reader,
scoped_refptr<base::SingleThreadTaskRunner> clipboard_task_runner) {
@@ -145,6 +146,7 @@ class ClipboardTextReader final : public ClipboardReader {
}
};
+// Reads HTML from the System Clipboard as a blob with text/html content.
class ClipboardHtmlReader final : public ClipboardReader {
public:
explicit ClipboardHtmlReader(SystemClipboard* system_clipboard,
@@ -181,14 +183,14 @@ class ClipboardHtmlReader final : public ClipboardReader {
}
worker_pool::PostTask(
FROM_HERE,
- CrossThreadBindOnce(&ClipboardHtmlReader::EncodeHTMLOnBackgroundThread,
+ CrossThreadBindOnce(&ClipboardHtmlReader::EncodeOnBackgroundThread,
std::move(sanitized_html),
WrapCrossThreadPersistent(this),
std::move(clipboard_task_runner_)));
}
private:
- static void EncodeHTMLOnBackgroundThread(
+ static void EncodeOnBackgroundThread(
String plain_text,
ClipboardHtmlReader* reader,
scoped_refptr<base::SingleThreadTaskRunner> clipboard_task_runner) {
@@ -217,6 +219,81 @@ class ClipboardHtmlReader final : public ClipboardReader {
}
};
+// Reads SVG from the System Clipboard as a blob with image/svg content.
+class ClipboardSvgReader final : public ClipboardReader {
+ public:
+ ClipboardSvgReader(SystemClipboard* system_clipboard,
+ ClipboardPromise* promise)
+ : ClipboardReader(system_clipboard, promise) {}
+ ~ClipboardSvgReader() override = default;
+
+ // This must be called on the main thread because XML DOM nodes can
+ // only be used on the main thread.
+ void Read() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ system_clipboard()->ReadSvg(
+ WTF::Bind(&ClipboardSvgReader::OnRead, WrapPersistent(this)));
+ }
+
+ private:
+ void OnRead(const String& svg_string) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ LocalFrame* frame = promise_->GetLocalFrame();
+ if (!frame) {
+ NextRead(Vector<uint8_t>());
+ return;
+ }
+
+ // Now sanitize the SVG string.
+ KURL url;
+ unsigned fragment_start = 0;
+ DocumentFragment* fragment = CreateSanitizedFragmentFromMarkupWithContext(
+ *frame->GetDocument(), svg_string, fragment_start, svg_string.length(),
+ url);
+ String sanitized_svg =
+ CreateMarkup(fragment, kIncludeNode, kResolveAllURLs);
+
+ if (sanitized_svg.IsEmpty()) {
+ NextRead(Vector<uint8_t>());
+ return;
+ }
+ worker_pool::PostTask(
+ FROM_HERE,
+ CrossThreadBindOnce(&ClipboardSvgReader::EncodeOnBackgroundThread,
+ std::move(sanitized_svg),
+ WrapCrossThreadPersistent(this),
+ std::move(clipboard_task_runner_)));
+ }
+
+ static void EncodeOnBackgroundThread(
+ String plain_text,
+ ClipboardSvgReader* reader,
+ scoped_refptr<base::SingleThreadTaskRunner> clipboard_task_runner) {
+ DCHECK(!IsMainThread());
+
+ // Encode WTF String to UTF-8, the standard text format for blobs.
+ StringUTF8Adaptor utf8_text(plain_text);
+ Vector<uint8_t> utf8_bytes;
+ utf8_bytes.ReserveInitialCapacity(utf8_text.size());
+ utf8_bytes.Append(utf8_text.data(), utf8_text.size());
+
+ PostCrossThreadTask(*clipboard_task_runner, FROM_HERE,
+ CrossThreadBindOnce(&ClipboardSvgReader::NextRead,
+ WrapCrossThreadPersistent(reader),
+ std::move(utf8_bytes)));
+ }
+
+ void NextRead(Vector<uint8_t> utf8_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ Blob* blob = nullptr;
+ if (utf8_bytes.size()) {
+ blob =
+ Blob::Create(utf8_bytes.data(), utf8_bytes.size(), kMimeTypeImageSvg);
+ }
+ promise_->OnRead(blob);
+ }
+};
} // anonymous namespace
// ClipboardReader functions.
@@ -231,6 +308,10 @@ ClipboardReader* ClipboardReader::Create(SystemClipboard* system_clipboard,
if (mime_type == kMimeTypeTextHTML)
return MakeGarbageCollected<ClipboardHtmlReader>(system_clipboard, promise);
+
+ if (mime_type == kMimeTypeImageSvg &&
+ RuntimeEnabledFeatures::ClipboardSvgEnabled())
+ return MakeGarbageCollected<ClipboardSvgReader>(system_clipboard, promise);
// The MIME type is not supported.
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
index fc3068284d3..3a438c2cee4 100644
--- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
+++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -18,6 +18,7 @@
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -165,6 +166,49 @@ class ClipboardHtmlWriter final : public ClipboardWriter {
}
};
+class ClipboardSvgWriter final : public ClipboardWriter {
+ public:
+ ClipboardSvgWriter(SystemClipboard* system_clipboard,
+ ClipboardPromise* promise)
+ : ClipboardWriter(system_clipboard, promise) {}
+ ~ClipboardSvgWriter() override = default;
+
+ private:
+ // This must be called on the main thread because XML DOM nodes can
+ // only be used on the main thread
+ void StartWrite(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ DOMArrayBuffer* svg_data) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ String svg_string =
+ String::FromUTF8(reinterpret_cast<const LChar*>(svg_data->Data()),
+ svg_data->ByteLengthAsSizeT());
+
+ // Now sanitize the SVG string.
+ KURL url;
+ unsigned fragment_start = 0;
+ unsigned fragment_end = svg_string.length();
+
+ Document* document = promise_->GetLocalFrame()->GetDocument();
+ DocumentFragment* fragment = CreateSanitizedFragmentFromMarkupWithContext(
+ *document, svg_string, fragment_start, fragment_end, url);
+ String sanitized_svg =
+ CreateMarkup(fragment, kIncludeNode, kResolveAllURLs);
+ Write(sanitized_svg);
+ }
+
+ void DecodeOnBackgroundThread(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ DOMArrayBuffer* html_data) override {
+ NOTREACHED() << "SVG's serializers cannot be used on background threads.";
+ }
+
+ void Write(const String& svg_html) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ system_clipboard()->WriteSvg(svg_html);
+ promise_->CompleteWriteRepresentation();
+ }
+};
// Writes a blob with arbitrary, unsanitized content to the System Clipboard.
class ClipboardRawDataWriter final : public ClipboardWriter {
public:
@@ -239,6 +283,10 @@ ClipboardWriter* ClipboardWriter::Create(SystemClipboard* system_clipboard,
if (mime_type == kMimeTypeTextHTML)
return MakeGarbageCollected<ClipboardHtmlWriter>(system_clipboard, promise);
+ if (mime_type == kMimeTypeImageSvg &&
+ RuntimeEnabledFeatures::ClipboardSvgEnabled())
+ return MakeGarbageCollected<ClipboardSvgWriter>(system_clipboard, promise);
+
NOTREACHED() << "Type " << mime_type << " was not implemented";
return nullptr;
}
@@ -282,7 +330,7 @@ bool ClipboardWriter::IsValidType(const String& type, bool is_raw) {
// TODO(https://crbug.com/1029857): Add support for other types.
return type == kMimeTypeImagePng || type == kMimeTypeTextPlain ||
- type == kMimeTypeTextHTML;
+ type == kMimeTypeTextHTML || type == kMimeTypeImageSvg;
}
void ClipboardWriter::WriteToSystem(Blob* blob) {
diff --git a/chromium/third_party/blink/renderer/modules/content_index/BUILD.gn b/chromium/third_party/blink/renderer/modules/content_index/BUILD.gn
index e58d6caaafd..05705efacb8 100644
--- a/chromium/third_party/blink/renderer/modules/content_index/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/content_index/BUILD.gn
@@ -18,5 +18,4 @@ blink_modules_sources("content_index") {
"service_worker_registration_content_index.cc",
"service_worker_registration_content_index.h",
]
- deps = [ "//third_party/blink/renderer/modules/service_worker" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn b/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn
index 031f804f9b4..412a1c44643 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/BUILD.gn
@@ -12,8 +12,6 @@ blink_modules_sources("cookie_store") {
"cookie_store.h",
"cookie_store_manager.cc",
"cookie_store_manager.h",
- "cookie_store_metrics.cc",
- "cookie_store_metrics.h",
"extendable_cookie_change_event.cc",
"extendable_cookie_change_event.h",
"global_cookie_store.cc",
@@ -22,8 +20,5 @@ blink_modules_sources("cookie_store") {
"service_worker_registration_cookies.h",
]
- deps = [
- "//third_party/blink/renderer/modules/service_worker",
- "//third_party/blink/renderer/platform",
- ]
+ deps = [ "//third_party/blink/renderer/platform" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/README.md b/chromium/third_party/blink/renderer/modules/cookie_store/README.md
index 1052f8881d6..6940568daf6 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/README.md
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/README.md
@@ -1,4 +1,16 @@
-This module implements the
-[Cookie Store API](https://github.com/WICG/cookie-store). The
-implementation is under active development, and its progress is tracked in
-[this OWP Launch bug](https://crbug.com/729800)
+# Cookie Store API
+
+This module contains the implementation of the
+[Cookie Store API](https://wicg.github.io/cookie-store).
+
+## Testing
+
+The Cookie Store API is primarily tested in
+[Web Platform Tests](https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/web_tests/external/wpt/cookie-store/).
+
+## Design Documents
+
+Please refer to the
+[explainer](https://github.com/WICG/cookie-store/blob/main/explainer.md) and
+[original design documentation](https://docs.google.com/document/d/1ak6JzOMMO5q3dXvu4mHFWR-LLvaDc09XDvdeJZLtZd4/)
+for more details.
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl
index 1946df4904f..049c5bd8009 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl
@@ -14,6 +14,10 @@
SecureContext
] interface CookieChangeEvent : Event {
constructor(DOMString type, optional CookieChangeEventInit eventInitDict = {});
- [MeasureAs=CookieStoreAPI] readonly attribute CookieList changed;
- [MeasureAs=CookieStoreAPI] readonly attribute CookieList deleted;
+ [
+ MeasureAs=CookieStoreAPI, SameObject, SaveSameObject
+ ] readonly attribute FrozenArray<CookieListItem> changed;
+ [
+ MeasureAs=CookieStoreAPI, SameObject, SaveSameObject
+ ] readonly attribute FrozenArray<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 ae1bd6304e4..ace49af90f1 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
@@ -18,7 +18,6 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/cookie_store/cookie_change_event.h"
-#include "third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.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/service_worker/service_worker_global_scope.h"
@@ -44,13 +43,8 @@ network::mojom::blink::CookieManagerGetOptionsPtr ToBackendOptions(
ExceptionState& exception_state) {
auto backend_options = network::mojom::blink::CookieManagerGetOptions::New();
- if (options->hasMatchType() && options->matchType() == "starts-with") {
- backend_options->match_type =
- network::mojom::blink::CookieMatchType::STARTS_WITH;
- } else {
- backend_options->match_type =
- network::mojom::blink::CookieMatchType::EQUALS;
- }
+ // TODO(crbug.com/1124499): Cleanup matchType after evaluation.
+ backend_options->match_type = network::mojom::blink::CookieMatchType::EQUALS;
if (options->hasName()) {
backend_options->name = options->name();
@@ -260,7 +254,6 @@ ScriptPromise CookieStore::getAll(ScriptState* script_state,
ExceptionState& exception_state) {
UseCounter::Count(CurrentExecutionContext(script_state->GetIsolate()),
WebFeature::kCookieStoreAPI);
- RecordMatchType(*options);
return DoRead(script_state, options, &CookieStore::GetAllForUrlToGetAllResult,
exception_state);
@@ -279,7 +272,11 @@ ScriptPromise CookieStore::get(ScriptState* script_state,
ExceptionState& exception_state) {
UseCounter::Count(CurrentExecutionContext(script_state->GetIsolate()),
WebFeature::kCookieStoreAPI);
- RecordMatchType(*options);
+
+ if (!options->hasName() && !options->hasUrl()) {
+ exception_state.ThrowTypeError("CookieStoreGetOptions must not be empty");
+ return ScriptPromise();
+ }
return DoRead(script_state, options, &CookieStore::GetAllForUrlToGetResult,
exception_state);
@@ -518,7 +515,7 @@ void CookieStore::StartObserving() {
// See https://bit.ly/2S0zRAS for task types.
auto task_runner =
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ GetExecutionContext()->GetTaskRunner(TaskType::kDOMManipulation);
backend_->AddChangeListener(
default_cookie_url_, default_site_for_cookies_, default_top_frame_origin_,
change_listener_receiver_.BindNewPipeAndPassRemote(task_runner), {});
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl
index 77a25d01e85..1202deb9df5 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_get_options.idl
@@ -4,15 +4,7 @@
// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md
-enum CookieMatchType {
- "equals",
- "starts-with"
-};
-
dictionary CookieStoreGetOptions {
USVString name;
USVString url;
- // TODO(ayui): Add default value "equals" back once we are done measuring
- // usage.
- CookieMatchType matchType;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc
index 0981ba80b37..dda14e457cd 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_manager.cc
@@ -16,7 +16,6 @@
#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/modules/cookie_store/cookie_change_event.h"
-#include "third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -51,14 +50,9 @@ mojom::blink::CookieChangeSubscriptionPtr ToBackendSubscription(
backend_subscription->url = default_cookie_url;
}
- if (subscription->hasMatchType() &&
- subscription->matchType() == "starts-with") {
- backend_subscription->match_type =
- network::mojom::blink::CookieMatchType::STARTS_WITH;
- } else {
- backend_subscription->match_type =
- network::mojom::blink::CookieMatchType::EQUALS;
- }
+ // TODO(crbug.com/1124499): Cleanup matchType after re-evaluation.
+ backend_subscription->match_type =
+ network::mojom::blink::CookieMatchType::EQUALS;
if (subscription->hasName()) {
backend_subscription->name = subscription->name();
@@ -78,20 +72,8 @@ CookieStoreGetOptions* ToCookieChangeSubscription(
CookieStoreGetOptions* subscription = CookieStoreGetOptions::Create();
subscription->setUrl(backend_subscription.url);
- if (backend_subscription.match_type !=
- network::mojom::blink::CookieMatchType::STARTS_WITH ||
- !backend_subscription.name.IsEmpty()) {
+ if (!backend_subscription.name.IsEmpty())
subscription->setName(backend_subscription.name);
- }
-
- switch (backend_subscription.match_type) {
- case network::mojom::blink::CookieMatchType::STARTS_WITH:
- subscription->setMatchType(WTF::String("starts-with"));
- break;
- case network::mojom::blink::CookieMatchType::EQUALS:
- subscription->setMatchType(WTF::String("equals"));
- break;
- }
return subscription;
}
@@ -121,7 +103,6 @@ ScriptPromise CookieStoreManager::subscribe(
Vector<mojom::blink::CookieChangeSubscriptionPtr> backend_subscriptions;
backend_subscriptions.ReserveInitialCapacity(subscriptions.size());
for (const CookieStoreGetOptions* subscription : subscriptions) {
- RecordMatchType(*subscription);
mojom::blink::CookieChangeSubscriptionPtr backend_subscription =
ToBackendSubscription(default_cookie_url_, subscription,
exception_state);
@@ -147,7 +128,6 @@ ScriptPromise CookieStoreManager::unsubscribe(
Vector<mojom::blink::CookieChangeSubscriptionPtr> backend_subscriptions;
backend_subscriptions.ReserveInitialCapacity(subscriptions.size());
for (const CookieStoreGetOptions* subscription : subscriptions) {
- RecordMatchType(*subscription);
mojom::blink::CookieChangeSubscriptionPtr backend_subscription =
ToBackendSubscription(default_cookie_url_, subscription,
exception_state);
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.cc b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.cc
deleted file mode 100644
index b221803c7f8..00000000000
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_cookie_store_get_options.h"
-
-namespace blink {
-
-// This enum describes the MatchType value specified by the user.
-enum class MatchTypeOption {
- // Do not change the meaning or ordering of these values because they are
- // being recorded in a UMA metric.
- kUnspecified = 0,
- kEquals = 1,
- kStartsWith = 2,
- kMaxValue = kStartsWith,
-};
-
-void RecordMatchType(const CookieStoreGetOptions& options) {
- MatchTypeOption uma_match_type;
- // TODO(crbug.com/1092328): Switch by V8CookieMatchType::Enum.
- if (!options.hasMatchType()) {
- uma_match_type = MatchTypeOption::kUnspecified;
- } else if (options.matchType() == "equals") {
- uma_match_type = MatchTypeOption::kEquals;
- } else if (options.matchType() == "starts-with") {
- uma_match_type = MatchTypeOption::kStartsWith;
- } else {
- NOTREACHED();
- // In case of an invalid value, we assume it's "equals" for the consistency
- // of UMA.
- uma_match_type = MatchTypeOption::kEquals;
- }
- UMA_HISTOGRAM_ENUMERATION("Blink.CookieStore.MatchType", uma_match_type);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h
deleted file mode 100644
index af2d5a66699..00000000000
--- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store_metrics.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_COOKIE_STORE_METRICS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_COOKIE_STORE_METRICS_H_
-
-namespace blink {
-
-class CookieStoreGetOptions;
-
-// Record explicitly set MatchType option with UMA.
-void RecordMatchType(const CookieStoreGetOptions& options);
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_COOKIE_STORE_METRICS_H_
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl b/chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl
index 15a32f41d44..72f5588a58b 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl
@@ -12,6 +12,10 @@
RuntimeEnabled=CookieStoreWorker
] interface ExtendableCookieChangeEvent : ExtendableEvent {
constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict = {});
- [MeasureAs=CookieStoreAPI] readonly attribute CookieList changed;
- [MeasureAs=CookieStoreAPI] readonly attribute CookieList deleted;
+ [
+ MeasureAs=CookieStoreAPI, SameObject, SaveSameObject
+ ] readonly attribute FrozenArray<CookieListItem> changed;
+ [
+ MeasureAs=CookieStoreAPI, SameObject, SaveSameObject
+ ] readonly attribute FrozenArray<CookieListItem> deleted;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc b/chromium/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc
index c9ebad6ecd3..6f252c4dfda 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc
@@ -52,7 +52,7 @@ class GlobalCookieStoreImpl final
mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend;
execution_context->GetBrowserInterfaceBroker().GetInterface(
backend.BindNewPipeAndPassReceiver(
- execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ execution_context->GetTaskRunner(TaskType::kDOMManipulation)));
cookie_store_ = MakeGarbageCollected<CookieStore>(execution_context,
std::move(backend));
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl
index 66ea991cc73..72c2d0cc851 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl
@@ -8,6 +8,6 @@
RuntimeEnabled=CookieStoreWorker,
ImplementedAs=GlobalCookieStore
] partial interface ServiceWorkerGlobalScope {
- [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
+ [SameObject] readonly attribute CookieStore cookieStore;
attribute EventHandler oncookiechange;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc
index 55be9dae057..71eccd487af 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.cc
@@ -45,21 +45,12 @@ class ServiceWorkerRegistrationCookiesImpl final
registration_->GetExecutionContext();
DCHECK(execution_context);
- // TODO(crbug.com/839117): Remove once Expose on partial interface is
- // supported or Origin Trial as ended.
- if (!execution_context->IsWindow() &&
- !execution_context->IsServiceWorkerGlobalScope()) {
- return nullptr;
- }
-
HeapMojoRemote<mojom::blink::CookieStore,
HeapMojoWrapperMode::kWithoutContextObserver>
backend(execution_context);
- // TODO(pwnall): Replace TaskType::kInternalDefault with the task queue in
- // the Cookie Store spec, once that spec is finalized.
execution_context->GetBrowserInterfaceBroker().GetInterface(
backend.BindNewPipeAndPassReceiver(
- execution_context->GetTaskRunner(TaskType::kInternalDefault)));
+ execution_context->GetTaskRunner(TaskType::kDOMManipulation)));
cookie_store_manager_ = MakeGarbageCollected<CookieStoreManager>(
registration_, std::move(backend));
}
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl
index 759306877f1..40bed0e19a1 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/service_worker_registration_cookies.idl
@@ -3,12 +3,9 @@
// found in the LICENSE file.
[
- // TODO(crbug.com/839117): Enable the following [Exposed] on the partial
- // interface declaration one it's supported.
- //
- // Exposed=(ServiceWorker,Window),
+ Exposed=(ServiceWorker,Window),
RuntimeEnabled=CookieStoreWorker,
ImplementedAs=ServiceWorkerRegistrationCookies
] partial interface ServiceWorkerRegistration {
- readonly attribute CookieStoreManager cookies;
+ [SameObject] readonly attribute CookieStoreManager cookies;
};
diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl b/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl
index 47cbbbe1d78..c86f9a4f77a 100644
--- a/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl
+++ b/chromium/third_party/blink/renderer/modules/cookie_store/window_cookie_store.idl
@@ -9,5 +9,5 @@
ImplementedAs=GlobalCookieStore,
SecureContext
] partial interface Window {
- [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
+ [SameObject] readonly attribute CookieStore cookieStore;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/DEPS b/chromium/third_party/blink/renderer/modules/credentialmanager/DEPS
index 685004288b2..a2f1dff5a83 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/DEPS
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+mojo/public",
+ "+services/metrics/public/cpp/metrics_utils.h",
"+services/metrics/public/cpp/ukm_builders.h",
"+services/metrics/public/cpp/ukm_source_id.h",
"-third_party/blink/renderer/modules",
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_inputs.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_inputs.idl
index 424918720f2..b4dbb6804c5 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_inputs.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_inputs.idl
@@ -7,15 +7,22 @@
dictionary AuthenticationExtensionsClientInputs {
// https://w3c.github.io/webauthn/#sctn-appid-extension
USVString appid;
+
// https://w3c.github.io/webauthn/#sctn-appid-exclude-extension
USVString appidExclude;
CableRegistrationData cableRegistration;
sequence<CableAuthenticationData> cableAuthentication;
+
// https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#sctn-hmac-secret-extension
boolean hmacCreateSecret;
+
// https://w3c.github.io/webauthn/#sctn-uvm-extension
boolean uvm;
+
// https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20190409.html#sctn-credProtect-extension
USVString credentialProtectionPolicy;
boolean enforceCredentialProtectionPolicy = false;
+
+ // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension
+ [RuntimeEnabled=WebAuthenticationResidentKeyRequirement] boolean credProps = false;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_outputs.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_outputs.idl
index ca1aa2e3413..cccbbf50074 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_outputs.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authentication_extensions_client_outputs.idl
@@ -2,14 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// https://w3c.github.io/webauthn/#dictdef-authenticationextensionsclientoutputs
-//typedef sequence<unsigned long> UvmEntry
typedef sequence<sequence<unsigned long>> UvmEntries;
+// https://w3c.github.io/webauthn/#dictdef-authenticationextensionsclientoutputs
dictionary AuthenticationExtensionsClientOutputs {
boolean appid;
+
// https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#sctn-hmac-secret-extension
boolean hmacCreateSecret;
+
// https://w3c.github.io/webauthn/#sctn-uvm-extension
UvmEntries uvm;
+
+ // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension
+ CredentialPropertiesOutput credProps;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl
index f16bdf62398..6dc869e9f66 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl
@@ -10,7 +10,7 @@
Exposed=Window
] interface AuthenticatorAttestationResponse : AuthenticatorResponse {
[SameObject] readonly attribute ArrayBuffer attestationObject;
- sequence<DOMString> getTransports();
+ [HighEntropy=Direct, Measure] sequence<DOMString> getTransports();
ArrayBuffer getAuthenticatorData();
ArrayBuffer? getPublicKey();
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl
index 59f69827910..0bf12ae88f7 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl
@@ -3,14 +3,12 @@
// found in the LICENSE file.
// https://w3c.github.io/webauthn/#enumdef-authenticatorattachment
-
enum AuthenticatorAttachment {
"platform",
"cross-platform"
};
// https://w3c.github.io/webauthn/#enumdef-userverificationrequirement
-
enum UserVerificationRequirement {
"required",
"preferred",
@@ -18,9 +16,10 @@ enum UserVerificationRequirement {
};
// https://w3c.github.io/webauthn/#dictdef-authenticatorselectioncriteria
-
dictionary AuthenticatorSelectionCriteria {
AuthenticatorAttachment authenticatorAttachment;
boolean requireResidentKey = false;
+ // A DOMString expressing a ResidentKeyRequirement.
+ [RuntimeEnabled=WebAuthenticationResidentKeyRequirement] DOMString residentKey;
UserVerificationRequirement userVerification;
};
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
index 45fc07b97d7..ff4c8a84b38 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
@@ -50,10 +50,6 @@ class MODULES_EXPORT CredentialManagerProxy
payments::mojom::blink::PaymentCredential* PaymentCredential();
- void FlushCredentialManagerConnectionForTesting() {
- credential_manager_.FlushForTesting();
- }
-
void Trace(Visitor*) const override;
// Must be called only with argument representing a valid
@@ -61,18 +57,10 @@ class MODULES_EXPORT CredentialManagerProxy
static CredentialManagerProxy* From(ScriptState*);
private:
- HeapMojoRemote<mojom::blink::Authenticator,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- authenticator_;
- HeapMojoRemote<mojom::blink::CredentialManager,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- credential_manager_;
- HeapMojoRemote<mojom::blink::SmsReceiver,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- sms_receiver_;
- HeapMojoRemote<payments::mojom::blink::PaymentCredential,
- HeapMojoWrapperMode::kForceWithoutContextObserver>
- payment_credential_;
+ HeapMojoRemote<mojom::blink::Authenticator> authenticator_;
+ HeapMojoRemote<mojom::blink::CredentialManager> credential_manager_;
+ HeapMojoRemote<mojom::blink::SmsReceiver> sms_receiver_;
+ HeapMojoRemote<payments::mojom::blink::PaymentCredential> payment_credential_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
index 2af684cd9dc..c9a4a7c797a 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/credentialmanager/password_credential.h"
#include "third_party/blink/renderer/modules/credentialmanager/public_key_credential.h"
#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace mojo {
@@ -40,19 +41,20 @@ using blink::mojom::blink::CableRegistration;
using blink::mojom::blink::CableRegistrationPtr;
using blink::mojom::blink::CredentialInfo;
using blink::mojom::blink::CredentialInfoPtr;
-using blink::mojom::blink::CredentialType;
using blink::mojom::blink::CredentialManagerError;
+using blink::mojom::blink::CredentialType;
using blink::mojom::blink::PublicKeyCredentialCreationOptionsPtr;
using blink::mojom::blink::PublicKeyCredentialDescriptor;
using blink::mojom::blink::PublicKeyCredentialDescriptorPtr;
-using blink::mojom::blink::PublicKeyCredentialRpEntity;
-using blink::mojom::blink::PublicKeyCredentialRpEntityPtr;
-using blink::mojom::blink::PublicKeyCredentialUserEntity;
-using blink::mojom::blink::PublicKeyCredentialUserEntityPtr;
using blink::mojom::blink::PublicKeyCredentialParameters;
using blink::mojom::blink::PublicKeyCredentialParametersPtr;
using blink::mojom::blink::PublicKeyCredentialRequestOptionsPtr;
+using blink::mojom::blink::PublicKeyCredentialRpEntity;
+using blink::mojom::blink::PublicKeyCredentialRpEntityPtr;
using blink::mojom::blink::PublicKeyCredentialType;
+using blink::mojom::blink::PublicKeyCredentialUserEntity;
+using blink::mojom::blink::PublicKeyCredentialUserEntityPtr;
+using blink::mojom::blink::ResidentKeyRequirement;
using blink::mojom::blink::UserVerificationRequirement;
namespace {
@@ -145,8 +147,7 @@ TypeConverter<CredentialManagerError, AuthenticatorStatus>::Convert(
return CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED;
case blink::mojom::blink::AuthenticatorStatus::EMPTY_ALLOW_CREDENTIALS:
return CredentialManagerError::ANDROID_EMPTY_ALLOW_CREDENTIALS;
- case blink::mojom::blink::AuthenticatorStatus::
- ANDROID_NOT_SUPPORTED_ERROR:
+ case blink::mojom::blink::AuthenticatorStatus::ANDROID_NOT_SUPPORTED_ERROR:
return CredentialManagerError::ANDROID_NOT_SUPPORTED_ERROR;
case blink::mojom::blink::AuthenticatorStatus::
USER_VERIFICATION_UNSUPPORTED:
@@ -249,6 +250,23 @@ String TypeConverter<String, AuthenticatorTransport>::Convert(
}
// static
+base::Optional<blink::mojom::blink::ResidentKeyRequirement>
+TypeConverter<base::Optional<blink::mojom::blink::ResidentKeyRequirement>,
+ String>::Convert(const String& requirement) {
+ if (requirement == "discouraged")
+ return ResidentKeyRequirement::DISCOURAGED;
+ if (requirement == "preferred")
+ return ResidentKeyRequirement::PREFERRED;
+ if (requirement == "required")
+ return ResidentKeyRequirement::REQUIRED;
+
+ // AuthenticatorSelection.resident_key is defined as DOMString expressing a
+ // ResidentKeyRequirement and unknown values must be treated as if the
+ // property were unset.
+ return base::nullopt;
+}
+
+// static
UserVerificationRequirement
TypeConverter<UserVerificationRequirement, String>::Convert(
const String& requirement) {
@@ -304,7 +322,18 @@ TypeConverter<AuthenticatorSelectionCriteriaPtr,
attachment = criteria.authenticatorAttachment();
mojo_criteria->authenticator_attachment =
ConvertTo<AuthenticatorAttachment>(attachment);
- mojo_criteria->require_resident_key = criteria.requireResidentKey();
+ base::Optional<ResidentKeyRequirement> resident_key;
+ if (criteria.hasResidentKey()) {
+ resident_key = ConvertTo<base::Optional<ResidentKeyRequirement>>(
+ criteria.residentKey());
+ }
+ if (resident_key) {
+ mojo_criteria->resident_key = *resident_key;
+ } else {
+ mojo_criteria->resident_key = criteria.requireResidentKey()
+ ? ResidentKeyRequirement::REQUIRED
+ : ResidentKeyRequirement::DISCOURAGED;
+ }
mojo_criteria->user_verification = UserVerificationRequirement::PREFERRED;
if (criteria.hasUserVerification()) {
mojo_criteria->user_verification = ConvertTo<UserVerificationRequirement>(
@@ -514,6 +543,11 @@ TypeConverter<PublicKeyCredentialCreationOptionsPtr,
extensions->enforceCredentialProtectionPolicy()) {
mojo_options->enforce_protection_policy = true;
}
+ if (extensions->credProps()) {
+ DCHECK(blink::RuntimeEnabledFeatures::
+ WebAuthenticationResidentKeyRequirementEnabled());
+ mojo_options->cred_props = true;
+ }
}
return mojo_options;
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
index 3307e6b3927..5414c53af7a 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
@@ -76,6 +76,14 @@ struct TypeConverter<String, blink::mojom::blink::AuthenticatorTransport> {
};
template <>
+struct TypeConverter<
+ base::Optional<blink::mojom::blink::ResidentKeyRequirement>,
+ String> {
+ static base::Optional<blink::mojom::blink::ResidentKeyRequirement> Convert(
+ const String&);
+};
+
+template <>
struct TypeConverter<blink::mojom::blink::UserVerificationRequirement, String> {
static blink::mojom::blink::UserVerificationRequirement Convert(
const String&);
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc
index 2fc79e0c3f5..75437613392 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/credentialmanager/credential_metrics.h"
#include "base/metrics/histogram_macros.h"
+#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
namespace blink {
@@ -22,7 +23,18 @@ void RecordSmsOutcome(SMSReceiverOutcome outcome,
UMA_HISTOGRAM_ENUMERATION("Blink.Sms.Receive.Outcome", outcome);
}
-void RecordSmsSuccessTime(base::TimeDelta duration) {
+void RecordSmsSuccessTime(base::TimeDelta duration,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder) {
+ DCHECK_NE(source_id, ukm::kInvalidSourceId);
+ DCHECK(ukm_recorder);
+
+ ukm::builders::SMSReceiver builder(source_id);
+ // Uses exponential bucketing for datapoints reflecting user activity.
+ builder.SetTimeSuccessMs(
+ ukm::GetExponentialBucketMinForUserTiming(duration.InMilliseconds()));
+ builder.Record(ukm_recorder);
+
UMA_HISTOGRAM_MEDIUM_TIMES("Blink.Sms.Receive.TimeSuccess", duration);
}
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h
index 3ad0b5eade9..869eaaceab9 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_metrics.h
@@ -28,7 +28,9 @@ void RecordSmsOutcome(SMSReceiverOutcome outcome,
// receives the SMS and presses verify to move on with the verification flow.
// This uses the same histogram as SmsReceiver API to provide continuity with
// previous iterations of the API.
-void RecordSmsSuccessTime(base::TimeDelta duration);
+void RecordSmsSuccessTime(base::TimeDelta duration,
+ ukm::SourceId source_id,
+ ukm::UkmRecorder* ukm_recorder);
// Records the time from when the API is called to when the user dismisses the
// infobar to abort SMS retrieval. This uses the same histogram as SmsReceiver
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_properties_output.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_properties_output.idl
new file mode 100644
index 00000000000..839b071dee1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_properties_output.idl
@@ -0,0 +1,8 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webauthn/#dictdef-credentialpropertiesoutput
+dictionary CredentialPropertiesOutput {
+ boolean rk;
+};
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 2b4c627ac1a..effe38050a5 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/sms/sms_receiver_outcome.h"
#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom-blink.h"
@@ -17,8 +18,10 @@
#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/modules/v8/v8_authentication_extensions_client_inputs.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_client_outputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authenticator_selection_criteria.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_credential_creation_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_credential_properties_output.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_credential_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_federated_credential_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_otp_credential_request_options.h"
@@ -53,9 +56,11 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/origin_access_entry.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
#if defined(OS_ANDROID)
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_rp_entity.h"
@@ -164,6 +169,10 @@ bool CheckSecurityRequirementsBeforeRequest(
"document. Feature Policy may be used to delegate Web "
"Authentication capabilities to cross-origin child frames."));
return false;
+ } else {
+ UseCounter::Count(
+ resolver->GetExecutionContext(),
+ WebFeature::kCredentialManagerCrossOriginPublicKeyGetRequest);
}
break;
}
@@ -433,6 +442,16 @@ void OnMakePublicKeyCredentialComplete(
if (credential->echo_hmac_create_secret) {
extension_outputs->setHmacCreateSecret(credential->hmac_create_secret);
}
+ if (credential->echo_cred_props) {
+ DCHECK(RuntimeEnabledFeatures::
+ WebAuthenticationResidentKeyRequirementEnabled());
+ CredentialPropertiesOutput* cred_props_output =
+ CredentialPropertiesOutput::Create();
+ if (credential->has_cred_props_rk) {
+ cred_props_output->setRk(credential->cred_props_rk);
+ }
+ extension_outputs->setCredProps(cred_props_output);
+ }
resolver->Resolve(MakeGarbageCollected<PublicKeyCredential>(
credential->info->id, raw_id, authenticator_response,
extension_outputs));
@@ -508,10 +527,12 @@ void OnSmsReceive(ScriptPromiseResolver* resolver,
ukm::SourceId source_id = window.UkmSourceID();
ukm::UkmRecorder* recorder = window.UkmRecorder();
- if (status == mojom::blink::SmsStatus::kTimeout) {
- RecordSmsOutcome(SMSReceiverOutcome::kTimeout, source_id, recorder);
+ if (status == mojom::blink::SmsStatus::kUnhandledRequest) {
+ RecordSmsOutcome(SMSReceiverOutcome::kUnhandledRequest, source_id,
+ recorder);
resolver->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kTimeoutError, "OTP retrieval timed out."));
+ DOMExceptionCode::kInvalidStateError,
+ "OTP retrieval request not handled."));
return;
} else if (status == mojom::blink::SmsStatus::kAborted) {
RecordSmsOutcome(SMSReceiverOutcome::kAborted, source_id, recorder);
@@ -525,7 +546,8 @@ void OnSmsReceive(ScriptPromiseResolver* resolver,
DOMExceptionCode::kAbortError, "OTP retrieval was cancelled."));
return;
}
- RecordSmsSuccessTime(base::TimeTicks::Now() - start_time);
+ RecordSmsSuccessTime(base::TimeTicks::Now() - start_time, source_id,
+ recorder);
RecordSmsOutcome(SMSReceiverOutcome::kSuccess, source_id, recorder);
resolver->Resolve(MakeGarbageCollected<OTPCredential>(otp));
}
@@ -595,9 +617,9 @@ void OnMakePublicKeyCredentialForPaymentComplete(
auto* payment_credential_remote =
CredentialManagerProxy::From(resolver->GetScriptState())
->PaymentCredential();
+ auto credential_id = credential->info->raw_id;
payment_credential_remote->StorePaymentCredential(
- std::move(payment_instrument), credential->info->raw_id,
- options->rp()->id(),
+ std::move(payment_instrument), credential_id, options->rp()->id(),
WTF::Bind(
&OnPaymentCredentialCreationComplete,
WTF::Passed(std::make_unique<ScopedPromiseResolver>(resolver)),
@@ -638,7 +660,8 @@ void CreatePublicKeyCredentialForPaymentCredential(
mojom::blink::AuthenticatorSelectionCriteria::New();
selection_criteria->authenticator_attachment =
mojom::blink::AuthenticatorAttachment::PLATFORM;
- selection_criteria->require_resident_key = false;
+ selection_criteria->resident_key =
+ mojom::blink::ResidentKeyRequirement::DISCOURAGED;
selection_criteria->user_verification =
mojom::blink::UserVerificationRequirement::REQUIRED;
mojo_options->authenticator_selection = std::move(selection_criteria);
@@ -679,15 +702,10 @@ void CreatePublicKeyCredentialForPaymentCredential(
mojo_options->user = mojom::blink::PublicKeyCredentialUserEntity::New();
mojo_options->user->name = options->instrument()->displayName();
- // There isn't explicity a WebAuthn 'user ID', so just convert the
- // instrument display name into a byte array and use that.
- const uint8_t* display_name_bytes =
- static_cast<const uint8_t*>(options->instrument()->displayName().Bytes());
- mojo_options->user->id = Vector<uint8_t>();
- mojo_options->user->id.AppendRange(
- display_name_bytes,
- display_name_bytes +
- options->instrument()->displayName().CharactersSizeInBytes());
+ static constexpr wtf_size_t kRandomUserIdSize = 32;
+ mojo_options->user->id = Vector<uint8_t>(kRandomUserIdSize);
+ base::RandBytes(mojo_options->user->id.data(), kRandomUserIdSize);
+
mojo_options->user->display_name = options->instrument()->displayName();
mojo_options->user->icon = KURL(options->instrument()->icon());
@@ -795,13 +813,20 @@ ScriptPromise CredentialsContainer::get(
"a credential"));
return promise;
}
+ if (options->publicKey()->extensions()->credProps()) {
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotSupportedError,
+ "The 'credProps' extension is only valid when creating "
+ "a credential"));
+ return promise;
+ }
}
if (!options->publicKey()->hasUserVerification()) {
resolver->GetFrame()->Console().AddMessage(MakeGarbageCollected<
ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kWarning,
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning,
"publicKey.userVerification was not set to any value in Web "
"Authentication navigator.credentials.get() call. This defaults to "
"'preferred', which is probably not what you want. If in doubt, set "
@@ -1057,8 +1082,8 @@ ScriptPromise CredentialsContainer::create(
->hasUserVerification()) {
resolver->GetFrame()->Console().AddMessage(MakeGarbageCollected<
ConsoleMessage>(
- mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kWarning,
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning,
"publicKey.authenticatorSelection.userVerification was not set to "
"any value in Web Authentication navigator.credentials.create() "
"call. This defaults to 'preferred', which is probably not what you "
@@ -1066,7 +1091,17 @@ ScriptPromise CredentialsContainer::create(
"https://chromium.googlesource.com/chromium/src/+/master/content/"
"browser/webauth/uv_preferred.md for details"));
}
-
+ if (options->publicKey()->hasAuthenticatorSelection() &&
+ options->publicKey()->authenticatorSelection()->hasResidentKey() &&
+ !mojo::ConvertTo<base::Optional<mojom::blink::ResidentKeyRequirement>>(
+ options->publicKey()->authenticatorSelection()->residentKey())) {
+ resolver->GetFrame()->Console().AddMessage(
+ MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "Ignoring unknown publicKey.authenticatorSelection.resident_key "
+ "value"));
+ }
auto mojo_options =
MojoPublicKeyCredentialCreationOptions::From(*options->publicKey());
if (!mojo_options) {
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
index b747bf3a4c1..a77304e7237 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
@@ -171,7 +171,6 @@ TEST(CredentialsContainerTest,
MockCredentialManager mock_credential_manager;
CredentialManagerTestingContext context(&mock_credential_manager);
- auto* proxy = CredentialManagerProxy::From(context.GetScriptState());
auto promise = MakeGarbageCollected<CredentialsContainer>()->get(
context.GetScriptState(), CredentialRequestOptions::Create());
mock_credential_manager.WaitForCallToGet();
@@ -179,7 +178,6 @@ TEST(CredentialsContainerTest,
context.Frame()->DomWindow()->FrameDestroyed();
mock_credential_manager.InvokeGetCallback();
- proxy->FlushCredentialManagerConnectionForTesting();
EXPECT_EQ(v8::Promise::kPending,
promise.V8Value().As<v8::Promise>()->State());
diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/idls.gni b/chromium/third_party/blink/renderer/modules/credentialmanager/idls.gni
index 875e786a302..474757066a2 100644
--- a/chromium/third_party/blink/renderer/modules/credentialmanager/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/credentialmanager/idls.gni
@@ -25,6 +25,7 @@ modules_dictionary_idl_files = [
"credential_creation_options.idl",
"credential_data.idl",
"credential_request_options.idl",
+ "credential_properties_output.idl",
"federated_credential_init.idl",
"federated_credential_request_options.idl",
"otp_credential_request_options.idl",
diff --git a/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn b/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
index fe5e78782e5..e7fa2d1a09a 100644
--- a/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/csspaint/BUILD.gn
@@ -30,4 +30,6 @@ blink_modules_sources("csspaint") {
"paint_worklet_proxy_client.cc",
"paint_worklet_proxy_client.h",
]
+
+ public_deps = [ "//third_party/blink/renderer/modules/canvas:canvas" ]
}
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 2229321bb5c..fecba43701e 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
@@ -48,10 +48,11 @@ PaintWorkletGlobalScopeProxy::PaintWorkletGlobalScopeProxy(
frame->Client()->CreateWorkerContentSettingsClient(),
window->AddressSpace(), OriginTrialContext::GetTokens(window).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault, module_responses_map,
+ mojom::blink::V8CacheOptions::kDefault, module_responses_map,
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
- window->GetAgentClusterID(), window->GetExecutionContextToken());
+ window->GetAgentClusterID(), window->GetExecutionContextToken(),
+ window->CrossOriginIsolatedCapability());
global_scope_ = PaintWorkletGlobalScope::Create(
frame, std::move(creation_params), *reporting_proxy_);
}
diff --git a/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc b/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
index 72eb5b7265a..c8431ee4bba 100644
--- a/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
+++ b/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
@@ -10,7 +10,9 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/events/pointer_event.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/geometry/dom_rect.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/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -97,14 +99,39 @@ void DelegatedInkTrailPresenter::updateInkTrailStartPoint(
layout_box = layout_view;
}
- // TODO(1052145): Move this further into the document lifecycle when layout
- // is up to date.
- PhysicalRect physical_rect_area = layout_box->LocalToAbsoluteRect(
+ // Intersect with the visible viewport so that the presentation area can't
+ // extend beyond the edges of the window or over the scrollbars. The frame
+ // visual viewport loop accounts for all iframe viewports, and the page visual
+ // viewport accounts for the full window. Convert everything to root frame
+ // coordinates in order to make sure offsets aren't lost along the way.
+ //
+ // TODO(1052145): Overflow and clip-path clips are ignored here, which results
+ // in delegated ink trails ignoring the clips and appearing incorrectly in
+ // some situations. This could also occur due to transformations, as the
+ // |presenation_area| is currently always a rectilinear bounding box. Ideally
+ // both of these situations are handled correctly, or the trail doesn't appear
+ // if we are unable to accurately render it.
+ PhysicalRect border_box_rect_absolute = layout_box->LocalToAbsoluteRect(
layout_box->PhysicalBorderBoxRect(), kTraverseDocumentBoundaries);
- gfx::RectF area(physical_rect_area.X().ToFloat(),
- physical_rect_area.Y().ToFloat(),
- physical_rect_area.Width().ToFloat(),
- physical_rect_area.Height().ToFloat());
+
+ while (layout_view->GetFrame()->OwnerLayoutObject()) {
+ PhysicalRect frame_visual_viewport_absolute =
+ layout_view->LocalToAbsoluteRect(
+ PhysicalRect(
+ layout_view->GetScrollableArea()->VisibleContentRect()),
+ kTraverseDocumentBoundaries);
+ border_box_rect_absolute.Intersect(frame_visual_viewport_absolute);
+
+ layout_view = layout_view->GetFrame()->OwnerLayoutObject()->View();
+ }
+
+ border_box_rect_absolute.Intersect(PhysicalRect(
+ local_frame_->GetPage()->GetVisualViewport().VisibleContentRect()));
+
+ gfx::RectF area(border_box_rect_absolute.X().ToFloat(),
+ border_box_rect_absolute.Y().ToFloat(),
+ border_box_rect_absolute.Width().ToFloat(),
+ border_box_rect_absolute.Height().ToFloat());
const double diameter_in_physical_pixels = style->diameter() * effective_zoom;
std::unique_ptr<viz::DelegatedInkMetadata> metadata =
diff --git a/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc b/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc
index 23169f624ba..4b974e7e3bd 100644
--- a/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter_unittest.cc
@@ -30,6 +30,7 @@ class TestDelegatedInkMetadata {
: area_(area) {
area_.Scale(device_pixel_ratio);
}
+ TestDelegatedInkMetadata() = default;
void ExpectEqual(TestDelegatedInkMetadata actual) const {
// LayoutUnits cast floats to ints, causing the actual point and area to be
@@ -64,7 +65,19 @@ DelegatedInkTrailPresenter* CreatePresenter(Element* element,
} // namespace
class DelegatedInkTrailPresenterUnitTest : public SimTest {
- protected:
+ public:
+ void SetWebViewSize(float width, float height) {
+ WebView().MainFrameWidget()->Resize(WebSize(width, height));
+ }
+
+ void SetWebViewSizeGreaterThanCanvas(float width, float height) {
+ // The presentation area is intersected with the visible content rect, so
+ // make sure that the page size is larger than the canvas to ensure it
+ // isn't clipped. Adding 1 to the height and width is enough to ensure that
+ // doesn't happen.
+ SetWebViewSize(width + 1, height + 1);
+ }
+
PointerEvent* CreatePointerMoveEvent(gfx::PointF pt) {
PointerEventInit* init = PointerEventInit::Create();
init->setClientX(pt.x());
@@ -84,9 +97,29 @@ class DelegatedInkTrailPresenterUnitTest : public SimTest {
}
};
+// Test scenarios with the presentation area extending beyond the edges of the
+// window to confirm it gets clipped correctly.
+class DelegatedInkTrailPresenterCanvasBeyondViewport
+ : public DelegatedInkTrailPresenterUnitTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ bool CanvasShouldBePastViewport() { return GetParam(); }
+ float GetViewportWidth() const { return kViewportWidth; }
+ float GetViewportHeight() const { return kViewportHeight; }
+ void SetWebViewSize() {
+ DelegatedInkTrailPresenterUnitTest::SetWebViewSize(kViewportWidth,
+ kViewportHeight);
+ }
+
+ private:
+ const float kViewportWidth = 175.f;
+ const float kViewportHeight = 180.f;
+};
+
// Confirm that all the information is collected and transformed correctly, if
// necessary. Numbers and color used were chosen arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, CollectAndPropagateMetadata) {
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
+ CollectAndPropagateMetadata) {
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
@@ -108,8 +141,16 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CollectAndPropagateMetadata) {
const float kCanvasWidth = 191.f;
const float kCanvasHeight = 234.f;
- TestDelegatedInkMetadata expected_metadata(
- gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight));
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kCanvasWidth, kCanvasHeight);
+ expected_metadata.SetArea(gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight));
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(
+ gfx::RectF(0, 0, GetViewportWidth(), GetViewportHeight()));
+ }
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
@@ -130,38 +171,10 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CollectAndPropagateMetadata) {
expected_metadata.ExpectEqual(GetActualMetadata());
}
-// Confirm that presentation area defaults to the size of the viewport.
-// Numbers and color used were chosen arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, PresentationAreaNotProvided) {
- const int kViewportHeight = 555;
- const int kViewportWidth = 333;
- WebView().MainFrameWidget()->Resize(WebSize(kViewportWidth, kViewportHeight));
-
- DelegatedInkTrailPresenter* presenter =
- CreatePresenter(nullptr, GetDocument().GetFrame());
- DCHECK(presenter);
-
- TestDelegatedInkMetadata expected_metadata(
- gfx::RectF(0, 0, kViewportWidth, kViewportHeight));
-
- InkTrailStyle style;
- style.setDiameter(3.6);
- style.setColor("yellow");
- expected_metadata.SetDiameter(style.diameter());
- expected_metadata.SetColor(SK_ColorYELLOW);
-
- gfx::PointF pt(70, 109);
- presenter->updateInkTrailStartPoint(
- ToScriptStateForMainWorld(GetDocument().GetFrame()),
- CreatePointerMoveEvent(pt), &style);
- expected_metadata.SetPoint(pt);
-
- expected_metadata.ExpectEqual(GetActualMetadata());
-}
-
// Confirm that everything is still calculated correctly when the
// DevicePixelRatio is not 1. Numbers and color used were chosen arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, NotDefaultDevicePixelRatio) {
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
+ NotDefaultDevicePixelRatio) {
const float kZoom = 1.7;
SetPageZoomFactor(kZoom);
@@ -186,8 +199,18 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, NotDefaultDevicePixelRatio) {
const float kCanvasWidth = 281.f;
const float kCanvasHeight = 190.f;
- TestDelegatedInkMetadata expected_metadata(
- gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight), kZoom);
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kCanvasWidth * kZoom,
+ kCanvasHeight * kZoom);
+ expected_metadata = TestDelegatedInkMetadata(
+ gfx::RectF(0, 0, kCanvasWidth, kCanvasHeight), kZoom);
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(
+ gfx::RectF(0, 0, GetViewportWidth(), GetViewportHeight()));
+ }
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
@@ -211,7 +234,7 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, NotDefaultDevicePixelRatio) {
// Confirm that the offset is correct. Numbers and color used were chosen
// arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasNotAtOrigin) {
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasNotAtOrigin) {
SimRequest main_resource("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
@@ -224,8 +247,8 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasNotAtOrigin) {
width: 250px;
height: 350px;
position: fixed;
- top: 375px;
- left: 166px;
+ top: 59px;
+ left: 16px;
}
</style>
<canvas id='canvas'></canvas>
@@ -235,11 +258,23 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasNotAtOrigin) {
const float kCanvasWidth = 250.f;
const float kCanvasHeight = 350.f;
- const float kCanvasTopOffset = 375.f;
- const float kCanvasLeftOffset = 166.f;
+ const float kCanvasTopOffset = 59.f;
+ const float kCanvasLeftOffset = 16.f;
- TestDelegatedInkMetadata expected_metadata(gfx::RectF(
- kCanvasLeftOffset, kCanvasTopOffset, kCanvasWidth, kCanvasHeight));
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kCanvasWidth + kCanvasLeftOffset,
+ kCanvasHeight + kCanvasTopOffset);
+ expected_metadata.SetArea(gfx::RectF(kCanvasLeftOffset, kCanvasTopOffset,
+ kCanvasWidth, kCanvasHeight));
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(
+ gfx::RectF(kCanvasLeftOffset, kCanvasTopOffset,
+ GetViewportWidth() - kCanvasLeftOffset,
+ GetViewportHeight() - kCanvasTopOffset));
+ }
DelegatedInkTrailPresenter* presenter = CreatePresenter(
GetDocument().getElementById("canvas"), GetDocument().GetFrame());
@@ -262,7 +297,7 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasNotAtOrigin) {
// Confirm that values, specifically offsets, are transformed correctly when
// the canvas is in an iframe. Numbers and color used were chosen arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasInIFrame) {
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, CanvasInIFrame) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -272,7 +307,7 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasInIFrame) {
body {
margin: 0;
}
- iframe {
+ #iframe {
width: 500px;
height: 500px;
position: fixed;
@@ -309,20 +344,35 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasInIFrame) {
const float kIframeBorder = 2.f;
const float kIframeLeftOffset = 57.f + kIframeBorder;
const float kIframeTopOffset = 26.f + kIframeBorder;
+ const float kIframeHeight = 500.f;
+ const float kIframeWidth = 500.f;
const float kCanvasLeftOffset = 16.f;
const float kCanvasTopOffset = 33.f;
const float kCanvasHeight = 250.f;
const float kCanvasWidth = 250.f;
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kIframeWidth + kIframeLeftOffset,
+ kIframeHeight + kIframeTopOffset);
+ expected_metadata.SetArea(gfx::RectF(kIframeLeftOffset + kCanvasLeftOffset,
+ kIframeTopOffset + kCanvasTopOffset,
+ kCanvasWidth, kCanvasHeight));
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(gfx::RectF(
+ kIframeLeftOffset + kCanvasLeftOffset,
+ kIframeTopOffset + kCanvasTopOffset,
+ GetViewportWidth() - (kIframeLeftOffset + kCanvasLeftOffset),
+ GetViewportHeight() - (kIframeTopOffset + kCanvasTopOffset)));
+ }
+
auto* iframe_element =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
Document* iframe_document = iframe_element->contentDocument();
- TestDelegatedInkMetadata expected_metadata(gfx::RectF(
- kIframeLeftOffset + kCanvasLeftOffset,
- kIframeTopOffset + kCanvasTopOffset, kCanvasWidth, kCanvasHeight));
-
DelegatedInkTrailPresenter* presenter = CreatePresenter(
iframe_localframe->GetDocument()->getElementById("canvas"),
iframe_document->GetFrame());
@@ -344,9 +394,136 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasInIFrame) {
expected_metadata.ExpectEqual(GetActualMetadata());
}
+// Confirm that values, specifically offsets, are transformed correctly when
+// the canvas is in a nested iframe. Numbers and color used were chosen
+// arbitrarily.
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport, NestedIframe) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+ SimRequest frame2_resource("https://example.com/iframe2.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #OuterIframe {
+ width: 500px;
+ height: 500px;
+ position: fixed;
+ top: 26px;
+ left: 57px;
+ }
+ </style>
+ <iframe id='OuterIframe' src='https://example.com/iframe.html'>
+ </iframe>
+ )HTML");
+
+ frame_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #InnerIframe {
+ width: 400px;
+ height: 400px;
+ position: fixed;
+ top: 11px;
+ left: 18px;
+ }
+ </style>
+ <iframe id='InnerIframe' src='https://example.com/iframe2.html'>
+ </iframe>
+ )HTML");
+
+ frame2_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ canvas {
+ width: 250px;
+ height: 250px;
+ position: fixed;
+ top: 28px;
+ left: 6px;
+ }
+ </style>
+ <canvas id='canvas'></canvas>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ // When creating the expected metadata, we have to take into account the
+ // offsets that are applied to the iframe that the canvas is in, and the 2px
+ // border around the iframe.
+ const float kIframeBorder = 2.f;
+ const float kOuterIframeLeftOffset = 57.f + kIframeBorder;
+ const float kOuterIframeTopOffset = 26.f + kIframeBorder;
+ const float kOuterIframeHeight = 500.f;
+ const float kOuterIframeWidth = 500.f;
+ const float kInnerIframeLeftOffset =
+ kOuterIframeLeftOffset + 18.f + kIframeBorder;
+ const float kInnerIframeTopOffset =
+ kOuterIframeTopOffset + 11.f + kIframeBorder;
+ const float kCanvasLeftOffset = 6.f;
+ const float kCanvasTopOffset = 28.f;
+ const float kCanvasHeight = 250.f;
+ const float kCanvasWidth = 250.f;
+
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kOuterIframeWidth + kOuterIframeLeftOffset,
+ kOuterIframeHeight + kOuterIframeTopOffset);
+ expected_metadata.SetArea(gfx::RectF(
+ kInnerIframeLeftOffset + kCanvasLeftOffset,
+ kInnerIframeTopOffset + kCanvasTopOffset, kCanvasWidth, kCanvasHeight));
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(gfx::RectF(
+ kInnerIframeLeftOffset + kCanvasLeftOffset,
+ kInnerIframeTopOffset + kCanvasTopOffset,
+ GetViewportWidth() - (kInnerIframeLeftOffset + kCanvasLeftOffset),
+ GetViewportHeight() - (kInnerIframeTopOffset + kCanvasTopOffset)));
+ }
+
+ auto* outer_iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("OuterIframe"));
+ auto* inner_iframe_element = To<HTMLIFrameElement>(
+ outer_iframe_element->contentDocument()->getElementById("InnerIframe"));
+ auto* iframe_localframe =
+ To<LocalFrame>(inner_iframe_element->ContentFrame());
+ Document* iframe_document = inner_iframe_element->contentDocument();
+
+ DelegatedInkTrailPresenter* presenter = CreatePresenter(
+ iframe_localframe->GetDocument()->getElementById("canvas"),
+ iframe_document->GetFrame());
+ DCHECK(presenter);
+
+ InkTrailStyle style;
+ style.setDiameter(100000.3);
+ style.setColor("yellow");
+ expected_metadata.SetDiameter(style.diameter());
+ expected_metadata.SetColor(SK_ColorYELLOW);
+
+ gfx::PointF pt(350, 375);
+ presenter->updateInkTrailStartPoint(
+ ToScriptStateForMainWorld(iframe_document->GetFrame()),
+ CreatePointerMoveEvent(pt), &style);
+ expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
+ pt.y() + kInnerIframeTopOffset));
+
+ expected_metadata.ExpectEqual(GetActualMetadata());
+}
+
// Confirm that values are correct when an iframe is used and presentation area
// isn't provided. Numbers and color used were chosen arbitrarily.
-TEST_F(DelegatedInkTrailPresenterUnitTest, IFrameNoPresentationArea) {
+TEST_P(DelegatedInkTrailPresenterCanvasBeyondViewport,
+ IFrameNoPresentationArea) {
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -356,7 +533,7 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, IFrameNoPresentationArea) {
body {
margin: 0;
}
- iframe {
+ #iframe {
width: 500px;
height: 500px;
position: fixed;
@@ -387,13 +564,25 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, IFrameNoPresentationArea) {
const float kIframeHeight = 500.f;
const float kIframeWidth = 500.f;
+ TestDelegatedInkMetadata expected_metadata;
+
+ if (!CanvasShouldBePastViewport()) {
+ SetWebViewSizeGreaterThanCanvas(kIframeWidth + kIframeLeftOffset,
+ kIframeHeight + kIframeTopOffset);
+ expected_metadata.SetArea(gfx::RectF(kIframeLeftOffset, kIframeTopOffset,
+ kIframeWidth, kIframeHeight));
+ } else {
+ SetWebViewSize();
+ expected_metadata.SetArea(
+ gfx::RectF(kIframeLeftOffset, kIframeTopOffset,
+ GetViewportWidth() - kIframeLeftOffset,
+ GetViewportHeight() - kIframeTopOffset));
+ }
+
Document* iframe_document =
To<HTMLIFrameElement>(GetDocument().getElementById("iframe"))
->contentDocument();
- TestDelegatedInkMetadata expected_metadata(gfx::RectF(
- kIframeLeftOffset, kIframeTopOffset, kIframeWidth, kIframeHeight));
-
DelegatedInkTrailPresenter* presenter =
CreatePresenter(nullptr, iframe_document->GetFrame());
DCHECK(presenter);
@@ -414,4 +603,333 @@ TEST_F(DelegatedInkTrailPresenterUnitTest, IFrameNoPresentationArea) {
expected_metadata.ExpectEqual(GetActualMetadata());
}
+INSTANTIATE_TEST_SUITE_P(,
+ DelegatedInkTrailPresenterCanvasBeyondViewport,
+ testing::Bool());
+
+// Confirm that presentation area defaults to the size of the viewport.
+// Numbers and color used were chosen arbitrarily.
+TEST_F(DelegatedInkTrailPresenterUnitTest, PresentationAreaNotProvided) {
+ const int kViewportHeight = 555;
+ const int kViewportWidth = 333;
+ SetWebViewSize(kViewportWidth, kViewportHeight);
+
+ DelegatedInkTrailPresenter* presenter =
+ CreatePresenter(nullptr, GetDocument().GetFrame());
+ DCHECK(presenter);
+
+ TestDelegatedInkMetadata expected_metadata(
+ gfx::RectF(0, 0, kViewportWidth, kViewportHeight));
+
+ InkTrailStyle style;
+ style.setDiameter(3.6);
+ style.setColor("yellow");
+ expected_metadata.SetDiameter(style.diameter());
+ expected_metadata.SetColor(SK_ColorYELLOW);
+
+ gfx::PointF pt(70, 109);
+ presenter->updateInkTrailStartPoint(
+ ToScriptStateForMainWorld(GetDocument().GetFrame()),
+ CreatePointerMoveEvent(pt), &style);
+ expected_metadata.SetPoint(pt);
+
+ expected_metadata.ExpectEqual(GetActualMetadata());
+}
+
+// Test that the presentation area is clipped correctly by the dimensions of
+// the iframe, even when the iframe and canvas each fit entirely within the
+// visual viewport.
+TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasExtendsOutsideOfIframe) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #iframe {
+ width: 150px;
+ height: 150px;
+ position: fixed;
+ top: 13px;
+ left: 19px;
+ }
+ </style>
+ <iframe id='iframe' src='https://example.com/iframe.html'>
+ </iframe>
+ )HTML");
+
+ frame_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ canvas {
+ width: 199px;
+ height: 202px;
+ }
+ </style>
+ <canvas id='canvas'></canvas>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ // When creating the expected metadata, we have to take into account the
+ // offsets that are applied to the iframe that the canvas is in, and the 2px
+ // border around the iframe.
+ const float kIframeBorder = 2.f;
+ const float kIframeLeftOffset = 19.f + kIframeBorder;
+ const float kIframeTopOffset = 13.f + kIframeBorder;
+ const float kIframeHeight = 150.f;
+ const float kIframeWidth = 150.f;
+ const float kCanvasHeight = 202.f;
+ const float kCanvasWidth = 199.f;
+
+ // Ensure that the webpage is larger than the iframe and canvas.
+ SetWebViewSize(kCanvasWidth + kIframeLeftOffset + 1,
+ kCanvasHeight + kIframeTopOffset + 1);
+
+ TestDelegatedInkMetadata expected_metadata(gfx::RectF(
+ kIframeLeftOffset, kIframeTopOffset, kIframeWidth, kIframeHeight));
+
+ auto* iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
+ auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
+ Document* iframe_document = iframe_element->contentDocument();
+
+ DelegatedInkTrailPresenter* presenter = CreatePresenter(
+ iframe_localframe->GetDocument()->getElementById("canvas"),
+ iframe_document->GetFrame());
+ DCHECK(presenter);
+
+ InkTrailStyle style;
+ style.setDiameter(99.999);
+ style.setColor("lime");
+ expected_metadata.SetDiameter(style.diameter());
+ expected_metadata.SetColor(SK_ColorGREEN);
+
+ gfx::PointF pt(102, 67);
+ presenter->updateInkTrailStartPoint(
+ ToScriptStateForMainWorld(iframe_document->GetFrame()),
+ CreatePointerMoveEvent(pt), &style);
+ expected_metadata.SetPoint(
+ gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
+
+ expected_metadata.ExpectEqual(GetActualMetadata());
+}
+
+// Test that the presentation area is clipped correctly when it is offset left
+// and above the iframe boundaries.
+TEST_F(DelegatedInkTrailPresenterUnitTest, CanvasLeftAndAboveIframeBoundaries) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #iframe {
+ width: 300px;
+ height: 301px;
+ position: fixed;
+ top: 13px;
+ left: 19px;
+ }
+ </style>
+ <iframe id='iframe' src='https://example.com/iframe.html'>
+ </iframe>
+ )HTML");
+
+ frame_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ canvas {
+ width: 189px;
+ height: 145px;
+ position: fixed;
+ top: -70px;
+ left: -99px;
+ }
+ </style>
+ <canvas id='canvas'></canvas>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ // When creating the expected metadata, we have to take into account the
+ // offsets that are applied to the iframe that the canvas is in, and the 2px
+ // border around the iframe.
+ const float kIframeBorder = 2.f;
+ const float kIframeLeftOffset = 19.f + kIframeBorder;
+ const float kIframeTopOffset = 13.f + kIframeBorder;
+ const float kIframeHeight = 301.f;
+ const float kIframeWidth = 300.f;
+ const float kCanvasHeight = 145.f;
+ const float kCanvasWidth = 189.f;
+ const float kCanvasLeftOffset = -99.f;
+ const float kCanvasTopOffset = -70.f;
+
+ // Ensure that the webpage is larger than the iframe.
+ SetWebViewSize(kIframeHeight + kIframeLeftOffset + 1,
+ kIframeWidth + kIframeTopOffset + 1);
+
+ TestDelegatedInkMetadata expected_metadata(gfx::RectF(
+ kIframeLeftOffset, kIframeTopOffset, kCanvasWidth + kCanvasLeftOffset,
+ kCanvasHeight + kCanvasTopOffset));
+
+ auto* iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
+ auto* iframe_localframe = To<LocalFrame>(iframe_element->ContentFrame());
+ Document* iframe_document = iframe_element->contentDocument();
+
+ DelegatedInkTrailPresenter* presenter = CreatePresenter(
+ iframe_localframe->GetDocument()->getElementById("canvas"),
+ iframe_document->GetFrame());
+ DCHECK(presenter);
+
+ InkTrailStyle style;
+ style.setDiameter(99.999);
+ style.setColor("lime");
+ expected_metadata.SetDiameter(style.diameter());
+ expected_metadata.SetColor(SK_ColorGREEN);
+
+ gfx::PointF pt(102, 67);
+ presenter->updateInkTrailStartPoint(
+ ToScriptStateForMainWorld(iframe_document->GetFrame()),
+ CreatePointerMoveEvent(pt), &style);
+ expected_metadata.SetPoint(
+ gfx::PointF(pt.x() + kIframeLeftOffset, pt.y() + kIframeTopOffset));
+
+ expected_metadata.ExpectEqual(GetActualMetadata());
+}
+
+// Confirm that values, specifically presentation area, are transformed
+// correctly when the iframe that the canvas is in is clipped by its parent
+// iframe. Numbers and color used were chosen arbitrarily.
+TEST_F(DelegatedInkTrailPresenterUnitTest, OuterIframeClipsInnerIframe) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+ SimRequest frame2_resource("https://example.com/iframe2.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #OuterIframe {
+ width: 500px;
+ height: 500px;
+ position: fixed;
+ top: 26px;
+ left: 57px;
+ }
+ </style>
+ <iframe id='OuterIframe' src='https://example.com/iframe.html'>
+ </iframe>
+ )HTML");
+
+ frame_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ #InnerIframe {
+ width: 400px;
+ height: 400px;
+ position: fixed;
+ top: 311px;
+ left: 334px;
+ }
+ </style>
+ <iframe id='InnerIframe' src='https://example.com/iframe2.html'>
+ </iframe>
+ )HTML");
+
+ frame2_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ body {
+ margin: 0;
+ }
+ canvas {
+ width: 250px;
+ height: 250px;
+ position: fixed;
+ top: 1px;
+ left: 2px;
+ }
+ </style>
+ <canvas id='canvas'></canvas>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ // When creating the expected metadata, we have to take into account the
+ // offsets that are applied to the iframe that the canvas is in, and the 2px
+ // border around the iframe.
+ const float kIframeBorder = 2.f;
+ const float kOuterIframeLeftOffset = 57.f + kIframeBorder;
+ const float kOuterIframeTopOffset = 26.f + kIframeBorder;
+ const float kOuterIframeHeight = 500.f;
+ const float kOuterIframeWidth = 500.f;
+ const float kInnerIframeLeftOffset =
+ kOuterIframeLeftOffset + 334.f + kIframeBorder;
+ const float kInnerIframeTopOffset =
+ kOuterIframeTopOffset + 311.f + kIframeBorder;
+ const float kCanvasLeftOffset = 2.f;
+ const float kCanvasTopOffset = 1.f;
+
+ // Ensure that the webpage is larger than the iframe and canvas.
+ const float kViewportWidth = kOuterIframeWidth + kOuterIframeLeftOffset + 1.f;
+ const float kViewportHeight =
+ kOuterIframeHeight + kOuterIframeTopOffset + 1.f;
+ SetWebViewSize(kViewportWidth, kViewportHeight);
+
+ TestDelegatedInkMetadata expected_metadata(
+ gfx::RectF(kInnerIframeLeftOffset + kCanvasLeftOffset,
+ kInnerIframeTopOffset + kCanvasTopOffset,
+ kOuterIframeWidth + kOuterIframeLeftOffset -
+ kInnerIframeLeftOffset - kCanvasLeftOffset,
+ kOuterIframeHeight + kOuterIframeTopOffset -
+ kInnerIframeTopOffset - kCanvasTopOffset));
+
+ auto* outer_iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("OuterIframe"));
+ auto* inner_iframe_element = To<HTMLIFrameElement>(
+ outer_iframe_element->contentDocument()->getElementById("InnerIframe"));
+ auto* iframe_localframe =
+ To<LocalFrame>(inner_iframe_element->ContentFrame());
+ Document* iframe_document = inner_iframe_element->contentDocument();
+
+ DelegatedInkTrailPresenter* presenter = CreatePresenter(
+ iframe_localframe->GetDocument()->getElementById("canvas"),
+ iframe_document->GetFrame());
+ DCHECK(presenter);
+
+ InkTrailStyle style;
+ style.setDiameter(19);
+ style.setColor("red");
+ expected_metadata.SetDiameter(style.diameter());
+ expected_metadata.SetColor(SK_ColorRED);
+
+ gfx::PointF pt(357, 401);
+ presenter->updateInkTrailStartPoint(
+ ToScriptStateForMainWorld(iframe_document->GetFrame()),
+ CreatePointerMoveEvent(pt), &style);
+ expected_metadata.SetPoint(gfx::PointF(pt.x() + kInnerIframeLeftOffset,
+ pt.y() + kInnerIframeTopOffset));
+
+ expected_metadata.ExpectEqual(GetActualMetadata());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn b/chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn
new file mode 100644
index 00000000000..d02d224a34a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("direct_sockets") {
+ sources = [
+ "navigator_socket.cc",
+ "navigator_socket.h",
+ ]
+}
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS b/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS
new file mode 100644
index 00000000000..39333436eb6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/OWNERS
@@ -0,0 +1,5 @@
+ericwilligers@chromium.org
+glenrob@chromium.org
+mgiuca@chromium.org
+
+# COMPONENT: Blink>Network
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/README.md b/chromium/third_party/blink/renderer/modules/direct_sockets/README.md
new file mode 100644
index 00000000000..72a9447b88a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/README.md
@@ -0,0 +1,6 @@
+This directory implements the Blink side of the [Direct Sockets
+API](https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md).
+
+It will connect to a DirectSocketsService Mojo service in the browser,
+which performs security checks, provides dialogs, and forwards requests to
+the Network service.
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/idls.gni b/chromium/third_party/blink/renderer/modules/direct_sockets/idls.gni
new file mode 100644
index 00000000000..763253e02e8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/idls.gni
@@ -0,0 +1,7 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+modules_dictionary_idl_files = [ "socket_options.idl" ]
+
+modules_dependency_idl_files = [ "navigator_socket.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc
new file mode 100644
index 00000000000..f6d7d6b3e03
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc
@@ -0,0 +1,267 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/direct_sockets/navigator_socket.h"
+
+#include "base/macros.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_socket_options.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_dom_window.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/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+class NavigatorSocket::PendingRequest final
+ : public GarbageCollected<PendingRequest> {
+ public:
+ PendingRequest(NavigatorSocket&, ScriptPromiseResolver&);
+
+ // TODO(crbug.com/905818): Resolve Promise<TCPSocket>
+ void TcpCallback(int32_t result);
+
+ // TODO(crbug.com/1119620): Resolve Promise<UDPSocket>
+ void UdpCallback(int32_t result);
+
+ void OnConnectionError();
+
+ void Trace(Visitor* visitor) const {
+ visitor->Trace(navigator_);
+ visitor->Trace(resolver_);
+ }
+
+ private:
+ WeakMember<NavigatorSocket> navigator_;
+ Member<ScriptPromiseResolver> resolver_;
+ FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
+ feature_handle_for_scheduler_;
+};
+
+NavigatorSocket::PendingRequest::PendingRequest(
+ NavigatorSocket& navigator_socket,
+ ScriptPromiseResolver& resolver)
+ : navigator_(&navigator_socket),
+ resolver_(&resolver),
+ feature_handle_for_scheduler_(
+ ExecutionContext::From(resolver_->GetScriptState())
+ ->GetScheduler()
+ ->RegisterFeature(
+ SchedulingPolicy::Feature::
+ kOutstandingNetworkRequestDirectSocket,
+ {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
+
+void NavigatorSocket::PendingRequest::TcpCallback(int32_t result) {
+ if (navigator_)
+ navigator_->pending_requests_.erase(this);
+
+ // TODO(crbug.com/905818): Compare with net::OK
+ if (result == 0) {
+ // TODO(crbug.com/905818): Resolve TCPSocket
+ NOTIMPLEMENTED();
+ resolver_->Resolve();
+ } else {
+ resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError, "Permission denied"));
+ }
+}
+
+void NavigatorSocket::PendingRequest::UdpCallback(int32_t result) {
+ if (navigator_)
+ navigator_->pending_requests_.erase(this);
+
+ // TODO(crbug.com/1119620): Compare with net::OK
+ if (result == 0) {
+ // TODO(crbug.com/1119620): Resolve UDPSocket
+ NOTIMPLEMENTED();
+ resolver_->Resolve();
+ } else {
+ resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotAllowedError, "Permission denied"));
+ }
+}
+
+void NavigatorSocket::PendingRequest::OnConnectionError() {
+ resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kAbortError,
+ "Internal error: could not connect to DirectSocketsService interface."));
+}
+
+const char NavigatorSocket::kSupplementName[] = "NavigatorSocket";
+
+NavigatorSocket::NavigatorSocket(ExecutionContext* context)
+ : ExecutionContextLifecycleStateObserver(context) {}
+
+// static
+NavigatorSocket& NavigatorSocket::From(ScriptState* script_state) {
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ NavigatorSocket* supplement =
+ Supplement<ExecutionContext>::From<NavigatorSocket>(context);
+ if (!supplement) {
+ supplement = MakeGarbageCollected<NavigatorSocket>(context);
+ ProvideTo(*context, supplement);
+ }
+ return *supplement;
+}
+
+// static
+ScriptPromise NavigatorSocket::openTCPSocket(ScriptState* script_state,
+ Navigator& navigator,
+ const SocketOptions* options,
+ ExceptionState& exception_state) {
+ return From(script_state)
+ .openTCPSocket(script_state, options, exception_state);
+}
+
+// static
+ScriptPromise NavigatorSocket::openUDPSocket(ScriptState* script_state,
+ Navigator& navigator,
+ const SocketOptions* options,
+ ExceptionState& exception_state) {
+ return From(script_state)
+ .openUDPSocket(script_state, options, exception_state);
+}
+
+void NavigatorSocket::ContextDestroyed() {}
+
+void NavigatorSocket::ContextLifecycleStateChanged(
+ mojom::blink::FrameLifecycleState state) {
+ // TODO(crbug.com/1120868) close connections when the lifecycle state is not
+ // "active".
+ NOTIMPLEMENTED();
+}
+
+void NavigatorSocket::Trace(Visitor* visitor) const {
+ visitor->Trace(service_remote_);
+ visitor->Trace(pending_requests_);
+ Supplement<ExecutionContext>::Trace(visitor);
+ ExecutionContextLifecycleStateObserver::Trace(visitor);
+}
+
+void NavigatorSocket::EnsureServiceConnected(LocalDOMWindow& window) {
+ DCHECK(RuntimeEnabledFeatures::DirectSocketsEnabled());
+
+ if (!service_remote_.is_bound()) {
+ window.GetFrame()->GetBrowserInterfaceBroker().GetInterface(
+ service_remote_.BindNewPipeAndPassReceiver(
+ window.GetTaskRunner(TaskType::kMiscPlatformAPI)));
+ service_remote_.set_disconnect_handler(WTF::Bind(
+ &NavigatorSocket::OnConnectionError, WrapWeakPersistent(this)));
+ DCHECK(service_remote_.is_bound());
+ }
+}
+
+// static
+mojom::blink::DirectSocketOptionsPtr NavigatorSocket::CreateSocketOptions(
+ const SocketOptions& options) {
+ auto socket_options = mojom::blink::DirectSocketOptions::New();
+
+ if (options.hasLocalAddress())
+ socket_options->local_hostname = options.localAddress();
+ if (options.hasLocalPort())
+ socket_options->local_port = options.localPort();
+
+ if (options.hasRemoteAddress())
+ socket_options->remote_hostname = options.remoteAddress();
+ if (options.hasRemotePort())
+ socket_options->remote_port = options.remotePort();
+
+ if (options.hasSendBufferSize())
+ socket_options->send_buffer_size = options.sendBufferSize();
+ if (options.hasReceiveBufferSize())
+ socket_options->receive_buffer_size = options.receiveBufferSize();
+
+ if (options.hasKeepAlive())
+ socket_options->keep_alive = options.keepAlive();
+ if (options.hasNoDelay())
+ socket_options->no_delay = options.noDelay();
+
+ return socket_options;
+}
+
+ScriptPromise NavigatorSocket::openTCPSocket(ScriptState* script_state,
+ const SocketOptions* options,
+ ExceptionState& exception_state) {
+ if (!OpenSocketPermitted(script_state, options, exception_state))
+ return ScriptPromise();
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ PendingRequest* pending =
+ MakeGarbageCollected<PendingRequest>(*this, *resolver);
+ pending_requests_.insert(pending);
+ ScriptPromise promise = resolver->Promise();
+
+ service_remote_->OpenTcpSocket(
+ CreateSocketOptions(*options),
+ WTF::Bind(&PendingRequest::TcpCallback, WrapPersistent(pending)));
+ return promise;
+}
+
+ScriptPromise NavigatorSocket::openUDPSocket(ScriptState* script_state,
+ const SocketOptions* options,
+ ExceptionState& exception_state) {
+ if (!OpenSocketPermitted(script_state, options, exception_state))
+ return ScriptPromise();
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ PendingRequest* pending =
+ MakeGarbageCollected<PendingRequest>(*this, *resolver);
+ pending_requests_.insert(pending);
+ ScriptPromise promise = resolver->Promise();
+
+ service_remote_->OpenUdpSocket(
+ CreateSocketOptions(*options),
+ WTF::Bind(&PendingRequest::UdpCallback, WrapPersistent(pending)));
+ return promise;
+}
+
+bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state,
+ const SocketOptions* options,
+ ExceptionState& exception_state) {
+ LocalDOMWindow* const window = script_state->ContextIsValid()
+ ? LocalDOMWindow::From(script_state)
+ : nullptr;
+ if (!window) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ "Current frame is detached.");
+ return false;
+ }
+
+ // TODO(crbug.com/1119600): Do not consume (or check) transient activation
+ // for reconnection attempts.
+ if (!LocalFrame::ConsumeTransientUserActivation(window->GetFrame())) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Must be handling a user gesture to open a socket.");
+ return false;
+ }
+
+ DCHECK(options);
+ if (!options->hasRemotePort()) {
+ exception_state.ThrowTypeError("remotePort was not specified.");
+ return false;
+ }
+
+ EnsureServiceConnected(*window);
+ return true;
+}
+
+void NavigatorSocket::OnConnectionError() {
+ for (auto& pending : pending_requests_) {
+ pending->OnConnectionError();
+ }
+ pending_requests_.clear();
+ service_remote_.reset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h
new file mode 100644
index 00000000000..ba618f51bd8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.h
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_NAVIGATOR_SOCKET_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_NAVIGATOR_SOCKET_H_
+
+#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ExceptionState;
+class LocalDOMWindow;
+class Navigator;
+class ScriptState;
+class SocketOptions;
+
+class MODULES_EXPORT NavigatorSocket final
+ : public GarbageCollected<NavigatorSocket>,
+ public Supplement<ExecutionContext>,
+ public ExecutionContextLifecycleStateObserver {
+ public:
+ static const char kSupplementName[];
+
+ explicit NavigatorSocket(ExecutionContext*);
+ ~NavigatorSocket() override = default;
+
+ NavigatorSocket(const NavigatorSocket&) = delete;
+ NavigatorSocket& operator=(const NavigatorSocket&) = delete;
+
+ // Gets, or creates, NavigatorSocket supplement on ExecutionContext.
+ // See platform/Supplementable.h
+ static NavigatorSocket& From(ScriptState*);
+
+ // Navigator partial interface
+ static ScriptPromise openTCPSocket(ScriptState*,
+ Navigator&,
+ const SocketOptions*,
+ ExceptionState&);
+
+ static ScriptPromise openUDPSocket(ScriptState*,
+ Navigator&,
+ const SocketOptions*,
+ ExceptionState&);
+
+ // ExecutionContextLifecycleStateObserver:
+ void ContextDestroyed() override;
+ void ContextLifecycleStateChanged(mojom::blink::FrameLifecycleState) override;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ class PendingRequest;
+
+ // Binds service_remote_ if not already bound.
+ void EnsureServiceConnected(LocalDOMWindow&);
+
+ static mojom::blink::DirectSocketOptionsPtr CreateSocketOptions(
+ const SocketOptions&);
+
+ ScriptPromise openTCPSocket(ScriptState*,
+ const SocketOptions*,
+ ExceptionState&);
+
+ ScriptPromise openUDPSocket(ScriptState*,
+ const SocketOptions*,
+ ExceptionState&);
+
+ // Updates exception state whenever returning false.
+ bool OpenSocketPermitted(ScriptState*, const SocketOptions*, ExceptionState&);
+
+ void OnConnectionError();
+
+ HeapMojoRemote<blink::mojom::blink::DirectSocketsService> service_remote_{
+ nullptr};
+
+ HeapHashSet<Member<PendingRequest>> pending_requests_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_NAVIGATOR_SOCKET_H_
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl
new file mode 100644
index 00000000000..e5373783827
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#tcp
+// https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#udp
+
+[
+ ImplementedAs=NavigatorSocket,
+ RuntimeEnabled=DirectSockets
+] partial interface Navigator {
+ // TODO(crbug.com/905818): Return Promise<TCPSocket>
+ [SecureContext, RaisesException, CallWith=ScriptState, Measure]
+ Promise<void> openTCPSocket(optional SocketOptions options = {});
+
+ // TODO(crbug.com/1119620): Return Promise<UDPSocket>
+ [SecureContext, RaisesException, CallWith=ScriptState, Measure]
+ Promise<void> openUDPSocket(optional SocketOptions options = {});
+};
diff --git a/chromium/third_party/blink/renderer/modules/direct_sockets/socket_options.idl b/chromium/third_party/blink/renderer/modules/direct_sockets/socket_options.idl
new file mode 100644
index 00000000000..646b3cd308b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/direct_sockets/socket_options.idl
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#tcp
+
+dictionary SocketOptions {
+ DOMString localAddress;
+ unsigned short localPort;
+
+ DOMString remoteAddress;
+ unsigned short remotePort;
+
+ unsigned long sendBufferSize;
+ unsigned long receiveBufferSize;
+
+ // These are only relevant for TCP:
+ boolean keepAlive;
+ boolean noDelay;
+};
diff --git a/chromium/third_party/blink/renderer/modules/encoding/README.md b/chromium/third_party/blink/renderer/modules/encoding/README.md
new file mode 100644
index 00000000000..ec7d73de6e8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/encoding/README.md
@@ -0,0 +1,11 @@
+# Encoding API
+
+This directory contains Blink's implementation of [the Encoding
+Standard API](https://encoding.spec.whatwg.org/#api).
+
+Actual encoding and decoding is delegated to implementations of the
+[WTF::TextCodec](../../platform/wtf/text/text_codec.h) interface in
+[platform/wtf/text](../../platform/wtf/text). For most encodings we then
+delegate to [ICU](../../../../icu). The [ISO-2022-JP
+encoding](https://encoding.spec.whatwg.org/#iso-2022-jp) implementation of ICU
+has been patched for better conformance with the Encoding Standard.
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 671ba323111..6e5698d3ab5 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
@@ -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/WICG/media-capabilities/blob/master/eme-extension-policy-check.md
+// https://wicg.github.io/hdcp-detection/
[
ImplementedAs=MediaKeysGetStatusForPolicy,
diff --git a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
index c398c53dc54..b9ffc211d61 100644
--- a/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -21,7 +21,6 @@ blink_modules_sources("exported") {
"//third_party/blink/renderer/modules/crypto",
"//third_party/blink/renderer/modules/filesystem",
"//third_party/blink/renderer/modules/mediastream",
- "//third_party/blink/renderer/modules/service_worker",
"//ui/accessibility:ax_enums_mojo_blink",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/exported/web_ax_context.cc b/chromium/third_party/blink/renderer/modules/exported/web_ax_context.cc
index 699672a30c2..f6e94b1ade8 100644
--- a/chromium/third_party/blink/renderer/modules/exported/web_ax_context.cc
+++ b/chromium/third_party/blink/renderer/modules/exported/web_ax_context.cc
@@ -18,6 +18,12 @@ WebAXContext::WebAXContext(WebDocument root_document)
WebAXContext::~WebAXContext() {}
WebAXObject WebAXContext::Root() const {
+ // It is an error to call AXContext::GetAXObjectCache() if the underlying
+ // document is no longer active, so early return in that case to prevent
+ // crashes that might otherwise happen in some cases (see crbug.com/1094576).
+ if (!private_->HasActiveDocument())
+ return WebAXObject();
+
return WebAXObject(
static_cast<AXObjectCacheImpl*>(&private_->GetAXObjectCache())->Root());
}
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 265e54cc323..7fe2931c653 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
@@ -30,7 +30,6 @@
#include "third_party/blink/public/web/web_ax_object.h"
-#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
@@ -39,6 +38,7 @@
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
@@ -101,16 +101,6 @@ class WebAXSparseAttributeClientAdapter : public AXSparseAttributeClient {
value);
}
- void AddIntAttribute(AXIntAttribute attribute, int32_t value) override {
- attribute_map_.AddIntAttribute(static_cast<WebAXIntAttribute>(attribute),
- value);
- }
-
- void AddUIntAttribute(AXUIntAttribute attribute, uint32_t value) override {
- attribute_map_.AddUIntAttribute(static_cast<WebAXUIntAttribute>(attribute),
- value);
- }
-
void AddStringAttribute(AXStringAttribute attribute,
const String& value) override {
attribute_map_.AddStringAttribute(
@@ -151,15 +141,23 @@ class ScopedActionAnnotator {
Persistent<AXObjectCacheImpl> cache_;
};
-static bool IsLayoutClean(Document* document) {
- if (!document || !document->View())
- return false;
- if (document->NeedsLayoutTreeUpdate())
- return false;
- if (document->View()->NeedsLayout())
- return false;
- return document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean;
+#if DCHECK_IS_ON()
+static void CheckLayoutClean(const Document* document) {
+ DCHECK(document);
+ LocalFrameView* view = document->View();
+ DCHECK(view);
+ DCHECK(!document->NeedsLayoutTreeUpdate());
+ LayoutView* lview = view->GetLayoutView();
+
+ DCHECK(!view->NeedsLayout())
+ << "\n Layout pending: " << view->LayoutPending()
+ << "\n Needs layout: " << (lview && lview->NeedsLayout());
+
+ DCHECK_GE(document->Lifecycle().GetState(), DocumentLifecycle::kLayoutClean)
+ << "Document lifecycle must be at LayoutClean or later, was "
+ << document->Lifecycle().GetState();
}
+#endif
void WebAXObject::Reset() {
private_.Reset();
@@ -194,18 +192,38 @@ int WebAXObject::GenerateAXID() const {
return private_->AXObjectCache().GenerateAXID();
}
-bool WebAXObject::UpdateLayoutAndCheckValidity() {
+// This method must be called before serializing any accessibility nodes, in
+// order to ensure that layout calls are not made at an unsafe time in the
+// document lifecycle.
+bool WebAXObject::MaybeUpdateLayoutAndCheckValidity() {
if (!IsDetached()) {
- Document* document = private_->GetDocument();
- if (!document || !document->View())
- return false;
- if (!document->View()->UpdateLifecycleToCompositingCleanPlusScrolling(
- DocumentUpdateReason::kAccessibility))
+ if (!MaybeUpdateLayoutAndCheckValidity(GetDocument()))
return false;
}
// Doing a layout can cause this object to be invalid, so check again.
- return !IsDetached();
+ return CheckValidity();
+}
+
+// Returns true if the object is valid and can be accessed.
+bool WebAXObject::CheckValidity() {
+ if (IsDetached())
+ return false;
+
+#if DCHECK_IS_ON()
+ Node* node = private_->GetNode();
+ if (!node)
+ return true;
+
+ // Has up-to-date layout info or is display-locked (content-visibility), which
+ // is handled as a special case inside of accessibility code.
+ Document* document = private_->GetDocument();
+ DCHECK(!document->NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(*node) ||
+ DisplayLockUtilities::NearestLockedExclusiveAncestor(*node))
+ << "Node needs layout update and is not display locked";
+#endif // DCHECK_IS_ON()
+
+ return true;
}
ax::mojom::DefaultActionVerb WebAXObject::Action() const {
@@ -260,11 +278,12 @@ void WebAXObject::GetSparseAXAttributes(
private_->GetSparseAXAttributes(adapter);
}
-void WebAXObject::Serialize(ui::AXNodeData* node_data) const {
+void WebAXObject::Serialize(ui::AXNodeData* node_data,
+ ui::AXMode accessibility_mode) const {
if (IsDetached())
return;
- private_->Serialize(node_data);
+ private_->Serialize(node_data, accessibility_mode);
}
bool WebAXObject::IsAnchor() const {
@@ -309,13 +328,6 @@ bool WebAXObject::IsControl() const {
return private_->IsControl();
}
-WebAXRestriction WebAXObject::Restriction() const {
- if (IsDetached())
- return kWebAXRestrictionNone;
-
- return static_cast<WebAXRestriction>(private_->Restriction());
-}
-
bool WebAXObject::IsFocused() const {
if (IsDetached())
return false;
@@ -785,7 +797,7 @@ void WebAXObject::Selection(bool& is_selection_backward,
if (IsDetached() || GetDocument().IsNull())
return;
- WebAXObject focus = FromWebDocumentFocused(GetDocument());
+ WebAXObject focus = FromWebDocumentFocused(GetDocument(), false);
if (focus.IsDetached())
return;
@@ -881,7 +893,7 @@ unsigned WebAXObject::SelectionEnd() const {
if (IsDetached() || GetDocument().IsNull())
return 0;
- WebAXObject focus = FromWebDocumentFocused(GetDocument());
+ WebAXObject focus = FromWebDocumentFocused(GetDocument(), false);
if (focus.IsDetached())
return 0;
@@ -902,7 +914,7 @@ unsigned WebAXObject::SelectionStart() const {
if (IsDetached() || GetDocument().IsNull())
return 0;
- WebAXObject focus = FromWebDocumentFocused(GetDocument());
+ WebAXObject focus = FromWebDocumentFocused(GetDocument(), false);
if (focus.IsDetached())
return 0;
@@ -1081,13 +1093,6 @@ bool WebAXObject::SupportsRangeValue() const {
return private_->IsRangeValueSupported();
}
-WebString WebAXObject::ValueDescription() const {
- if (IsDetached())
- return WebString();
-
- return private_->ValueDescription();
-}
-
bool WebAXObject::ValueForRange(float* out_value) const {
if (IsDetached())
return false;
@@ -1142,7 +1147,9 @@ WebString WebAXObject::ComputedStyleDisplay() const {
if (IsDetached())
return WebString();
- DCHECK(IsLayoutClean(private_->GetDocument()));
+#if DCHECK_IS_ON()
+ CheckLayoutClean(private_->GetDocument());
+#endif
Node* node = private_->GetNode();
if (!node || node->IsDocumentNode())
@@ -1173,34 +1180,6 @@ bool WebAXObject::AccessibilityIsIncludedInTree() const {
return private_->AccessibilityIsIncludedInTree();
}
-int WebAXObject::AriaColumnCount() const {
- if (IsDetached())
- return 0;
-
- return private_->IsTableLikeRole() ? private_->AriaColumnCount() : 0;
-}
-
-unsigned WebAXObject::AriaColumnIndex() const {
- if (IsDetached())
- return 0;
-
- return private_->AriaColumnIndex();
-}
-
-int WebAXObject::AriaRowCount() const {
- if (IsDetached())
- return 0;
-
- return private_->IsTableLikeRole() ? private_->AriaRowCount() : 0;
-}
-
-unsigned WebAXObject::AriaRowIndex() const {
- if (IsDetached())
- return 0;
-
- return private_->AriaRowIndex();
-}
-
unsigned WebAXObject::ColumnCount() const {
if (IsDetached())
return false;
@@ -1377,9 +1356,9 @@ void WebAXObject::Markers(WebVector<ax::mojom::MarkerType>& types,
if (IsDetached())
return;
- Vector<DocumentMarker::MarkerType> marker_types;
- Vector<AXRange> marker_ranges;
- private_->Markers(marker_types, marker_ranges);
+ VectorOf<DocumentMarker::MarkerType> marker_types;
+ VectorOf<AXRange> marker_ranges;
+ private_->GetDocumentMarkers(&marker_types, &marker_ranges);
DCHECK_EQ(marker_types.size(), marker_ranges.size());
WebVector<ax::mojom::MarkerType> web_marker_types(marker_types.size());
@@ -1486,20 +1465,22 @@ void WebAXObject::Dropeffects(
}
void WebAXObject::GetRelativeBounds(WebAXObject& offset_container,
- WebFloatRect& bounds_in_container,
+ gfx::RectF& bounds_in_container,
SkMatrix44& container_transform,
bool* clips_children) const {
if (IsDetached())
return;
- DCHECK(IsLayoutClean(private_->GetDocument()));
+#if DCHECK_IS_ON()
+ CheckLayoutClean(private_->GetDocument());
+#endif
AXObject* container = nullptr;
FloatRect bounds;
private_->GetRelativeBounds(&container, bounds, container_transform,
clips_children);
offset_container = WebAXObject(container);
- bounds_in_container = WebFloatRect(bounds);
+ bounds_in_container = gfx::RectF(bounds);
}
void WebAXObject::GetAllObjectsWithChangedBounds(
@@ -1582,13 +1563,6 @@ void WebAXObject::HandleAutofillStateChanged(
private_->HandleAutofillStateChanged(state);
}
-int WebAXObject::GetDOMNodeId() const {
- if (IsDetached())
- return 0;
-
- return private_->GetDOMNodeId();
-}
-
WebString WebAXObject::ToString(bool verbose) const {
if (IsDetached())
return WebString();
@@ -1653,7 +1627,12 @@ WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) {
}
// static
-WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document) {
+WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document,
+ bool update_layout_if_necessary) {
+ if (update_layout_if_necessary &&
+ !MaybeUpdateLayoutAndCheckValidity(web_document)) {
+ return WebAXObject();
+ }
const Document* document = web_document.ConstUnwrap<Document>();
auto* cache = To<AXObjectCacheImpl>(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->GetOrCreate(document->GetLayoutView()))
@@ -1670,10 +1649,56 @@ WebAXObject WebAXObject::FromWebDocumentByID(const WebDocument& web_document,
// static
WebAXObject WebAXObject::FromWebDocumentFocused(
- const WebDocument& web_document) {
+ const WebDocument& web_document,
+ bool update_layout_if_necessary) {
+ if (update_layout_if_necessary &&
+ !MaybeUpdateLayoutAndCheckValidity(web_document)) {
+ return WebAXObject();
+ }
const Document* document = web_document.ConstUnwrap<Document>();
auto* cache = To<AXObjectCacheImpl>(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->FocusedObject()) : WebAXObject();
}
+// static
+void WebAXObject::UpdateLayout(const WebDocument& web_document) {
+ const Document* document = web_document.ConstUnwrap<Document>();
+ if (!document || !document->View())
+ return;
+ DCHECK(document->View());
+ DCHECK(document->ExistingAXObjectCache());
+ if (document->NeedsLayoutTreeUpdate() || document->View()->NeedsLayout() ||
+ document->Lifecycle().GetState() <
+ DocumentLifecycle::kCompositingAssignmentsClean ||
+ document->ExistingAXObjectCache()->IsDirty()) {
+ document->View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kAccessibility);
+ }
+}
+
+// static
+bool WebAXObject::MaybeUpdateLayoutAndCheckValidity(
+ const WebDocument& web_document) {
+ const Document* document = web_document.ConstUnwrap<Document>();
+ if (!document || !document->View())
+ return false;
+
+ if (document->NeedsLayoutTreeUpdate() || document->View()->NeedsLayout() ||
+ document->Lifecycle().GetState() <
+ DocumentLifecycle::kCompositingAssignmentsClean) {
+ // Note: this always alters the lifecycle, because
+ // RunAccessibilityLifecyclePhase() will be called.
+ if (!document->View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kAccessibility)) {
+ return false;
+ }
+ } else {
+#if DCHECK_IS_ON()
+ CheckLayoutClean(document);
+#endif
+ }
+
+ return true;
+}
+
} // namespace blink
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 2c6ad697040..da9e4d57f17 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
@@ -221,7 +221,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
nullptr /* OriginTrialTokens */, worker_start_data->devtools_worker_token,
std::move(worker_settings),
// Generate the full code cache in the first execution of the script.
- kV8CacheOptionsFullCodeWithoutHeatCheck,
+ mojom::blink::V8CacheOptions::kFullCodeWithoutHeatCheck,
nullptr /* worklet_module_respones_map */,
std::move(browser_interface_broker), BeginFrameProviderParams(),
nullptr /* parent_feature_policy */,
@@ -264,7 +264,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
// > "classic": Fetch a classic worker script given job's serialized script
// > url, job's client, "serviceworker", and the to-be-created environment
// > settings object for this service worker.
- case mojom::ScriptType::kClassic:
+ case mojom::blink::ScriptType::kClassic:
worker_thread_->FetchAndRunClassicScript(
worker_start_data->script_url,
nullptr /* worker_main_script_load_params */,
@@ -276,7 +276,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread(
// > "module": Fetch a module worker script graph given job’s serialized
// > script url, job’s client, "serviceworker", "omit", and the
// > to-be-created environment settings object for this service worker.
- case mojom::ScriptType::kModule:
+ case mojom::blink::ScriptType::kModule:
worker_thread_->FetchAndRunModuleScript(
worker_start_data->script_url,
nullptr /* worker_main_script_load_params */,
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/BUILD.gn b/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn
index d6b32ae2c98..38f13af4bea 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/BUILD.gn
@@ -4,7 +4,7 @@
import("//third_party/blink/renderer/modules/modules.gni")
-blink_modules_sources("native_file_system") {
+blink_modules_sources("file_system_access") {
sources = [
"data_transfer_item_native_file_system.cc",
"data_transfer_item_native_file_system.h",
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/DEPS b/chromium/third_party/blink/renderer/modules/file_system_access/DEPS
index 9e4bdfb62b3..70275dcd3a7 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/DEPS
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/DEPS
@@ -3,5 +3,5 @@ include_rules = [
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_target_modules.h",
"+third_party/blink/renderer/modules/modules_export.h",
- "+third_party/blink/renderer/modules/native_file_system",
+ "+third_party/blink/renderer/modules/file_system_access",
]
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/OWNERS b/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS
index 65bf4bfeb2f..427d68bda9b 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/OWNERS
@@ -1,4 +1,4 @@
-file://content/browser/native_file_system/OWNERS
+file://content/browser/file_system_access/OWNERS
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>FileSystem
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/README.md b/chromium/third_party/blink/renderer/modules/file_system_access/README.md
index 4787d052cd1..2771fa3b09b 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/README.md
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/README.md
@@ -1,19 +1,19 @@
-# Native File System API
+# File System Access API
-This directory contains the renderer side implementation of the native file
-system API.
+This directory contains the renderer side implementation of the file
+system access API.
## Related directories
-[`//content/browser/native_file_system/`](../../../content/browser/native_file_system)
+[`//content/browser/file_system_access/`](../../../content/browser/file_system_access)
contains the browser side implementation and
-[`blink/public/mojom/native_file_system`](../../../third_party/blink/public/mojom/native_file_system)
+[`blink/public/mojom/file_system_access`](../../../third_party/blink/public/mojom/file_system_access)
contains the mojom interfaces for these APIs.
## APIs In this directory
-This directory contains the implementation of the new and still under
-development [Native File System API](https://wicg.github.io/native-file-system/).
+This directory contains the implementation of the
+[File System Access API](https://wicg.github.io/file-system-access/).
It consists of the following parts:
@@ -21,7 +21,7 @@ It consists of the following parts:
these interfaces mimic the old `Entry` interfaces, but expose a more modern
promisified API.
- * ` getOriginPrivateDirectory`: An entry point that gives access to the same
+ * `StorageManager.getDirectory`: An entry point that gives access to the same
sandboxed filesystem as what is available through the old API.
* `FileSystemWritableFileStream`: a more modern API with similar functionality to the
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc
index 1637c8b0805..f897c3d15d0 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.cc
@@ -2,25 +2,25 @@
// 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/native_file_system/data_transfer_item_native_file_system.h"
+#include "third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_drag_drop_token.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_drag_drop_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_transfer_token.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/clipboard/data_object_item.h"
#include "third_party/blink/renderer/core/clipboard/data_transfer.h"
#include "third_party/blink/renderer/core/clipboard/data_transfer_item.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h
index 64d320845d7..e917182897a 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
#include "third_party/blink/renderer/core/clipboard/data_transfer_item.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
@@ -21,4 +21,4 @@ class DataTransferItemNativeFileSystem {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_DATA_TRANSFER_ITEM_NATIVE_FILE_SYSTEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl
index 48a9f1d7376..48a9f1d7376 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/data_transfer_item_native_file_system.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/data_transfer_item_native_file_system.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/directory_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl
index 3ebc626cee2..3ebc626cee2 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/directory_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_picker_accept_type.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl
index dc3f82282b7..dc3f82282b7 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_picker_accept_type.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_accept_type.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl
index 7bb6d45d657..7bb6d45d657 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_picker_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl
index df0834cd8b0..df0834cd8b0 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_directory_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl
index 505b2a85eee..c63eac8c403 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_directory_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.idl
@@ -18,20 +18,10 @@
NativeFileSystemDirectoryIterator keys();
NativeFileSystemDirectoryIterator values();
- [CallWith=ScriptState, RuntimeEnabled=LegacyNativeFileSystem, ImplementedAs=getFileHandle]
- Promise<FileSystemFileHandle> getFile(USVString name, optional FileSystemGetFileOptions options = {});
- [CallWith=ScriptState, RuntimeEnabled=LegacyNativeFileSystem, ImplementedAs=getDirectoryHandle]
- Promise<FileSystemDirectoryHandle> getDirectory(USVString name, optional FileSystemGetDirectoryOptions options = {});
-
[CallWith=ScriptState] Promise<FileSystemFileHandle> getFileHandle(USVString name, optional FileSystemGetFileOptions options = {});
[CallWith=ScriptState] Promise<FileSystemDirectoryHandle> getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});
- [CallWith=ScriptState, RuntimeEnabled=LegacyNativeFileSystem] object getEntries();
-
[CallWith=ScriptState] Promise<void> removeEntry(USVString name, optional FileSystemRemoveOptions options = {});
[CallWith=ScriptState, Measure] Promise<sequence<USVString>?> resolve(FileSystemHandle possibleChild);
-
- [CallWith=ScriptState, Measure, RaisesException, RuntimeEnabled=LegacyNativeFileSystem]
- static Promise<FileSystemDirectoryHandle> getSystemDirectory(GetSystemDirectoryOptions options);
};
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
index b24362e53ef..b24362e53ef 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_directory_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl
index 529b8dd2e8f..529b8dd2e8f 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_directory_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_directory_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_file_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl
index 57c5a7d0043..57c5a7d0043 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_get_file_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_get_file_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
index afb45e8aadc..1cab690071b 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
@@ -19,8 +19,6 @@ enum FileSystemHandleKind {
// Brand checking APIs because javascript makes it otherwise really hard to
// figure out what type an object is when you don't know in which global
// (i.e. iframe) the object was created.
- [RuntimeEnabled=LegacyNativeFileSystem] readonly attribute boolean isFile;
- [RuntimeEnabled=LegacyNativeFileSystem] readonly attribute boolean isDirectory;
readonly attribute FileSystemHandleKind kind;
readonly attribute USVString name;
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle_permission_descriptor.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl
index c4762fc1568..c4762fc1568 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_handle_permission_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_handle_permission_descriptor.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_remove_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl
index f3f856600cb..f3f856600cb 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_remove_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_remove_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_writable_file_stream.idl b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl
index e09e63d9cfa..e09e63d9cfa 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/file_system_writable_file_stream.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/file_system_writable_file_stream.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
index 7f7554e6689..0622d1d5931 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.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/modules/native_file_system/global_native_file_system.h"
+#include "third_party/blink/renderer/modules/file_system_access/global_native_file_system.h"
#include <utility>
@@ -10,10 +10,8 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_choose_file_system_entries_options.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_choose_file_system_entries_options_accepts.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_file_picker_accept_type.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_open_file_picker_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_save_file_picker_options.h"
@@ -23,9 +21,9 @@
#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/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -36,35 +34,6 @@ namespace blink {
namespace {
-mojom::blink::ChooseFileSystemEntryType ConvertChooserType(const String& input,
- bool multiple) {
- if (input == "open-file" || input == "openFile") {
- return multiple
- ? mojom::blink::ChooseFileSystemEntryType::kOpenMultipleFiles
- : mojom::blink::ChooseFileSystemEntryType::kOpenFile;
- }
- if (input == "save-file" || input == "saveFile")
- return mojom::blink::ChooseFileSystemEntryType::kSaveFile;
- if (input == "open-directory" || input == "openDirectory")
- return mojom::blink::ChooseFileSystemEntryType::kOpenDirectory;
- NOTREACHED();
- return mojom::blink::ChooseFileSystemEntryType::kOpenFile;
-}
-
-Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts(
- const HeapVector<Member<ChooseFileSystemEntriesOptionsAccepts>>& accepts) {
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> result;
- result.ReserveInitialCapacity(accepts.size());
- for (const auto& a : accepts) {
- result.emplace_back(
- blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New(
- a->hasDescription() ? a->description() : g_empty_string,
- a->hasMimeTypes() ? a->mimeTypes() : Vector<String>(),
- a->hasExtensions() ? a->extensions() : Vector<String>()));
- }
- return result;
-}
-
constexpr bool IsHTTPWhitespace(UChar chr) {
return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
}
@@ -234,29 +203,6 @@ ScriptPromise ShowFilePickerImpl(
} // namespace
// static
-ScriptPromise GlobalNativeFileSystem::chooseFileSystemEntries(
- ScriptState* script_state,
- LocalDOMWindow& window,
- const ChooseFileSystemEntriesOptions* options,
- ExceptionState& exception_state) {
- UseCounter::Count(window, WebFeature::kFileSystemPickerMethod);
-
- VerifyIsAllowedToShowFilePicker(window, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
- if (options->hasAccepts())
- accepts = ConvertAccepts(options->accepts());
-
- return ShowFilePickerImpl(
- script_state, window,
- ConvertChooserType(options->type(), options->multiple()),
- std::move(accepts), !options->excludeAcceptAllOption(),
- options->multiple());
-}
-
-// static
ScriptPromise GlobalNativeFileSystem::showOpenFilePicker(
ScriptState* script_state,
LocalDOMWindow& window,
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h
index 5dca39488b1..e0ee3bca43e 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system.h
@@ -2,15 +2,14 @@
// 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_NATIVE_FILE_SYSTEM_GLOBAL_NATIVE_FILE_SYSTEM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_GLOBAL_NATIVE_FILE_SYSTEM_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_NATIVE_FILE_SYSTEM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_NATIVE_FILE_SYSTEM_H_
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
-class ChooseFileSystemEntriesOptions;
class OpenFilePickerOptions;
class SaveFilePickerOptions;
class DirectoryPickerOptions;
@@ -23,12 +22,6 @@ class GlobalNativeFileSystem {
STATIC_ONLY(GlobalNativeFileSystem);
public:
- static ScriptPromise chooseFileSystemEntries(
- ScriptState*,
- LocalDOMWindow&,
- const ChooseFileSystemEntriesOptions*,
- ExceptionState&);
-
static ScriptPromise showOpenFilePicker(ScriptState*,
LocalDOMWindow&,
const OpenFilePickerOptions*,
@@ -45,4 +38,4 @@ class GlobalNativeFileSystem {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_GLOBAL_NATIVE_FILE_SYSTEM_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_GLOBAL_NATIVE_FILE_SYSTEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system_test.cc b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc
index cd028a4e22e..3ef59b97a23 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/global_native_file_system_test.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/global_native_file_system_test.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/native_file_system/global_native_file_system.h"
+#include "third_party/blink/renderer/modules/file_system_access/global_native_file_system.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.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/html/forms/html_button_element.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/idls.gni b/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni
index 420a6e67b3e..a3b719a6670 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/idls.gni
@@ -11,8 +11,6 @@ modules_idl_files = [
]
modules_dictionary_idl_files = [
- "choose_file_system_entries_options.idl",
- "choose_file_system_entries_options_accepts.idl",
"directory_picker_options.idl",
"file_picker_accept_type.idl",
"file_picker_options.idl",
@@ -21,7 +19,6 @@ modules_dictionary_idl_files = [
"file_system_get_file_options.idl",
"file_system_handle_permission_descriptor.idl",
"file_system_remove_options.idl",
- "get_system_directory_options.idl",
"open_file_picker_options.idl",
"save_file_picker_options.idl",
"write_params.idl",
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc
index 1bebd1f3189..2e008314ac7 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.cc
@@ -2,14 +2,14 @@
// 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/native_file_system/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_handle.h"
@@ -19,18 +19,14 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
-namespace {
-// The name to use for the root directory of a sandboxed file system.
-constexpr const char kSandboxRootDirectoryName[] = "";
-} // namespace
using mojom::blink::NativeFileSystemErrorPtr;
@@ -210,57 +206,6 @@ ScriptPromise NativeFileSystemDirectoryHandle::resolve(
return result;
}
-// static
-ScriptPromise NativeFileSystemDirectoryHandle::getSystemDirectory(
- ScriptState* script_state,
- const GetSystemDirectoryOptions* options,
- ExceptionState& exception_state) {
- ExecutionContext* context = ExecutionContext::From(script_state);
- if (!context->GetSecurityOrigin()->CanAccessNativeFileSystem()) {
- if (context->IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin)) {
- exception_state.ThrowSecurityError(
- "System directory access is denied because the context is "
- "sandboxed and lacks the 'allow-same-origin' flag.");
- return ScriptPromise();
- } else {
- exception_state.ThrowSecurityError("System directory access is denied.");
- return ScriptPromise();
- }
- }
-
- auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ScriptPromise result = resolver->Promise();
-
- // TODO(mek): Cache mojo::Remote<mojom::blink::NativeFileSystemManager>
- // associated with an ExecutionContext, so we don't have to request a new one
- // for each operation, and can avoid code duplication between here and other
- // uses.
- mojo::Remote<mojom::blink::NativeFileSystemManager> manager;
- context->GetBrowserInterfaceBroker().GetInterface(
- manager.BindNewPipeAndPassReceiver());
-
- auto* raw_manager = manager.get();
- raw_manager->GetSandboxedFileSystem(WTF::Bind(
- [](ScriptPromiseResolver* resolver,
- mojo::Remote<mojom::blink::NativeFileSystemManager>,
- NativeFileSystemErrorPtr result,
- mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle>
- handle) {
- ExecutionContext* context = resolver->GetExecutionContext();
- if (!context)
- return;
- if (result->status != mojom::blink::NativeFileSystemStatus::kOk) {
- native_file_system_error::Reject(resolver, *result);
- return;
- }
- resolver->Resolve(MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
- context, kSandboxRootDirectoryName, std::move(handle)));
- },
- WrapPersistent(resolver), std::move(manager)));
-
- return result;
-}
-
mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
NativeFileSystemDirectoryHandle::Transfer() {
mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> result;
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h
index 6e60c092067..d3a18ea1afd 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h
@@ -2,19 +2,18 @@
// 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_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
namespace blink {
class FileSystemGetDirectoryOptions;
class FileSystemGetFileOptions;
class FileSystemRemoveOptions;
-class GetSystemDirectoryOptions;
class NativeFileSystemDirectoryIterator;
class NativeFileSystemDirectoryHandle final : public NativeFileSystemHandle {
@@ -46,10 +45,6 @@ class NativeFileSystemDirectoryHandle final : public NativeFileSystemHandle {
ScriptPromise resolve(ScriptState*, NativeFileSystemHandle* possible_child);
- static ScriptPromise getSystemDirectory(ScriptState*,
- const GetSystemDirectoryOptions*,
- ExceptionState&);
-
mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> Transfer()
override;
@@ -79,4 +74,4 @@ class NativeFileSystemDirectoryHandle final : public NativeFileSystemHandle {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc
index 7a408895b79..17b84cc5daa 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h
index 310ecb3386b..256822f4af7 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
#include "base/files/file.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -62,4 +62,4 @@ class NativeFileSystemDirectoryIterator final
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_DIRECTORY_ITERATOR_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.idl b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl
index 7d8f424cdc6..59a4c983865 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_iterator.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_directory_iterator.idl
@@ -6,7 +6,7 @@
// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
ActiveScriptWrappable,
RuntimeEnabled=NativeFileSystem
] interface NativeFileSystemDirectoryIterator {
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc
index 6a4f2762e84..97c366d6f88 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h
index 362018649cd..f7aa988b0c2 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_error.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_error.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_ERROR_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_ERROR_H_
#include "base/files/file.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink-forward.h"
namespace blink {
class ScriptPromiseResolver;
@@ -25,4 +25,4 @@ void Reject(ScriptPromiseResolver* resolver,
} // namespace native_file_system_error
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_ERROR_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc
index 9419f3b555b..5ec47c8057a 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_transfer_token.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_create_writer_options.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fileapi/file.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/file_metadata.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h
index 47fbd767254..47ef04abc10 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom-blink.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom-blink.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
namespace blink {
@@ -56,4 +56,4 @@ class NativeFileSystemFileHandle final : public NativeFileSystemHandle {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc
index e60d5309b70..fc363132f2f 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.cc
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_handle_permission_descriptor.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h
index 45219361e56..526b941f0a1 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_HANDLE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_HANDLE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_HANDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_HANDLE_H_
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink-forward.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink-forward.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_transfer_token.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
@@ -69,4 +69,4 @@ class NativeFileSystemHandle : public ScriptWrappable,
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_HANDLE_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_HANDLE_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.cc
index 49ae32fef81..ad07ebb79c8 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.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/modules/native_file_system/native_file_system_underlying_sink.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -12,8 +12,8 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_write_params.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h
index cac18d80062..8d231fc658d 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
@@ -66,4 +66,4 @@ class NativeFileSystemUnderlyingSink final : public UnderlyingSinkBase {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_UNDERLYING_SINK_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.cc
index 4eff753c11e..64c6c2076f3 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.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/modules/native_file_system/native_file_system_writable_file_stream.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/streams/count_queuing_strategy.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_underlying_sink.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_underlying_sink.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h
index 3a037f3e34f..fe4ee8c8718 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/native_file_system_writable_file_stream.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom-blink.h"
#include "third_party/blink/renderer/bindings/modules/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string_or_write_params.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
@@ -43,4 +43,4 @@ class NativeFileSystemWritableFileStream final : public WritableStream {
};
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/open_file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl
index 96456f757a8..96456f757a8 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/open_file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/open_file_picker_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/save_file_picker_options.idl b/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl
index d18f9d01f73..d18f9d01f73 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/save_file_picker_options.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/save_file_picker_options.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.cc b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.cc
index 2506dcd34fb..39de3ac0567 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.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/modules/native_file_system/storage_manager_native_file_system.h"
+#include "third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h"
#include <utility>
@@ -10,11 +10,11 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_directory_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_error.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.h b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.h
index 308d6d6cd36..300eef493de 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.h
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.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_NATIVE_FILE_SYSTEM_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -26,4 +26,4 @@ class StorageManagerNativeFileSystem {
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILE_SYSTEM_ACCESS_STORAGE_MANAGER_NATIVE_FILE_SYSTEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl
index f3a36d59739..f3a36d59739 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/storage_manager_native_file_system.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/storage_manager_native_file_system.idl
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/window_native_file_system.idl b/chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl
index ad2c5142c8b..e2d65ef614e 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/window_native_file_system.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/window_native_file_system.idl
@@ -9,10 +9,6 @@
RuntimeEnabled=NativeFileSystem,
ImplementedAs=GlobalNativeFileSystem
] partial interface Window {
- [CallWith=ScriptState, Measure, RaisesException, RuntimeEnabled=LegacyNativeFileSystem]
- Promise<(FileSystemHandle or sequence<FileSystemHandle>)>
- chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options = {});
-
[CallWith=ScriptState, RaisesException, Measure]
Promise<sequence<FileSystemFileHandle>> showOpenFilePicker(
optional OpenFilePickerOptions options = {});
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/write_params.idl b/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl
index 9e6a39c7f52..9e6a39c7f52 100644
--- a/chromium/third_party/blink/renderer/modules/native_file_system/write_params.idl
+++ b/chromium/third_party/blink/renderer/modules/file_system_access/write_params.idl
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn b/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn
index edfe648b40d..49d30b126d3 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn
@@ -66,6 +66,7 @@ blink_modules_sources("filesystem") {
deps = [
"//components/services/filesystem/public/mojom:mojom_blink",
+ "//services/metrics/public/cpp:ukm_builders",
"//third_party/blink/renderer/platform",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/DEPS b/chromium/third_party/blink/renderer/modules/filesystem/DEPS
index e8bdd831680..0baabac330a 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/DEPS
+++ b/chromium/third_party/blink/renderer/modules/filesystem/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+base/files/file.h",
+ "+services/metrics/public/cpp",
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/event_target_modules.h",
"+third_party/blink/renderer/modules/filesystem",
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_entry.idl b/chromium/third_party/blink/renderer/modules/filesystem/directory_entry.idl
index 25846d52640..cac0275247c 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/directory_entry.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_entry.idl
@@ -30,7 +30,7 @@
// https://wicg.github.io/entries-api/#api-directoryentry
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DirectoryEntry : Entry {
DirectoryReader createReader();
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_entry_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/directory_entry_sync.idl
index eb86bbbd6df..ab0ea3f99bf 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/directory_entry_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_entry_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-DirectoryEntrySync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DirectoryEntrySync : EntrySync {
DirectoryReaderSync createReader();
[RaisesException] FileEntrySync getFile(DOMString? path, FileSystemFlags flags);
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.idl b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.idl
index 7d7288a1c3e..259585b3ac2 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-DirectoryReader
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DirectoryReader {
// TODO(crbug.com/841185): |errorCallback| is not nullable in the spec.
[MeasureAs=DeprecatedFileSystemRead]
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.idl
index b8123af5448..b42223bc076 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-DirectoryReaderSync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DirectoryReaderSync {
[RaisesException] sequence<EntrySync> readEntries();
};
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.idl b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.idl
index 1695f5b19bf..ada7b2af930 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.idl
@@ -32,7 +32,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-FileSystem
[
ActiveScriptWrappable,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DOMFileSystem {
readonly attribute DOMString name;
readonly attribute DirectoryEntry root;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.idl
index f106f6936f6..5b0d21edd72 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-FileSystemSync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DOMFileSystemSync {
readonly attribute DOMString name;
readonly attribute DirectoryEntrySync root;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
index 406dec2b526..3312630ba15 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
+++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
@@ -25,6 +25,9 @@
#include "third_party/blink/renderer/modules/filesystem/dom_window_file_system.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 "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h"
@@ -74,10 +77,19 @@ void DOMWindowFileSystem::webkitRequestFileSystem(
return;
}
+ auto* ukm_recorder = window.document()->UkmRecorder();
+ const ukm::SourceId source_id = window.document()->UkmSourceID();
+
if (file_system_type == mojom::blink::FileSystemType::kTemporary) {
UseCounter::Count(window, WebFeature::kRequestedFileSystemTemporary);
+ ukm::builders::FileSystemAPI_WebRequest(source_id)
+ .SetTemporary(true)
+ .Record(ukm_recorder->Get());
} else if (file_system_type == mojom::blink::FileSystemType::kPersistent) {
UseCounter::Count(window, WebFeature::kRequestedFileSystemPersistent);
+ ukm::builders::FileSystemAPI_WebRequest(source_id)
+ .SetPersistent(true)
+ .Record(ukm_recorder->Get());
}
auto success_callback_wrapper =
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/entry.idl b/chromium/third_party/blink/renderer/modules/filesystem/entry.idl
index dae22a8edd7..b9b51a55d7d 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/entry.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/entry.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-Entry
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface Entry {
readonly attribute boolean isFile;
readonly attribute boolean isDirectory;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/entry_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/entry_sync.idl
index 2b60af90f96..6b18537bd7c 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/entry_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/entry_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-EntrySync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EntrySync {
readonly attribute boolean isFile;
readonly attribute boolean isDirectory;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_entry.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_entry.idl
index 579837703c6..33bb7c15db0 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_entry.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_entry.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-FileEntry
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface FileEntry : Entry {
// TODO(crbug.com/841185): |errorCallback| is not nullable in the spec.
void createWriter(FileWriterCallback successCallback,
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_entry_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_entry_sync.idl
index af2ceb99227..42901105957 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_entry_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_entry_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-FileEntrySync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface FileEntrySync : EntrySync {
[RaisesException] File file();
[RaisesException] FileWriterSync createWriter();
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 63ef4642e6e..3fad596fd2f 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
@@ -422,11 +422,16 @@ void FileSystemDispatcher::Cancel(int request_id_to_cancel,
std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
return;
}
- cancellable_operations_.find(request_id_to_cancel)
- ->value->Value()
- ->Cancel(WTF::Bind(&FileSystemDispatcher::DidCancel,
- WrapWeakPersistent(this), std::move(callback),
- request_id_to_cancel));
+ auto& remote =
+ cancellable_operations_.find(request_id_to_cancel)->value->Value();
+ if (!remote.is_bound()) {
+ RemoveOperationRemote(request_id_to_cancel);
+ std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
+ return;
+ }
+ remote->Cancel(WTF::Bind(&FileSystemDispatcher::DidCancel,
+ WrapWeakPersistent(this), std::move(callback),
+ request_id_to_cancel));
}
void FileSystemDispatcher::CreateSnapshotFile(
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.idl
index 828ff99fd83..49e63e1271d 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.idl
@@ -32,7 +32,7 @@
// https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#idl-def-FileWriter
[
ActiveScriptWrappable,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface FileWriter : EventTarget {
// ready states
const unsigned short INIT = 0;
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.idl
index 463d0dd2ebe..5a480d0380a 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#idl-def-FileWriterSync
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface FileWriterSync {
// synchronous write/modify methods
[RaisesException] void write(Blob data);
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 538a725e00d..c2f6c4812a2 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
@@ -107,7 +107,9 @@ void LocalFileSystem::RequestFileSystemAccessInternal(
if (!client) {
std::move(callback).Run(true);
} else {
- client->RequestFileSystemAccessAsync(std::move(callback));
+ client->AllowStorageAccess(
+ WebContentSettingsClient::StorageType::kFileSystem,
+ std::move(callback));
}
return;
}
@@ -116,7 +118,8 @@ void LocalFileSystem::RequestFileSystemAccessInternal(
if (!client) {
std::move(callback).Run(true);
} else {
- std::move(callback).Run(client->RequestFileSystemAccessSync());
+ std::move(callback).Run(client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kFileSystem));
}
return;
}
diff --git a/chromium/third_party/blink/renderer/modules/filesystem/metadata.idl b/chromium/third_party/blink/renderer/modules/filesystem/metadata.idl
index d9afd54d328..934ab546d6f 100644
--- a/chromium/third_party/blink/renderer/modules/filesystem/metadata.idl
+++ b/chromium/third_party/blink/renderer/modules/filesystem/metadata.idl
@@ -30,7 +30,7 @@
// https://www.w3.org/TR/2012/WD-file-system-api-20120417/#idl-def-Metadata
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface Metadata {
[CallWith=ScriptState, Measure] readonly attribute object modificationTime;
readonly attribute unsigned long long size;
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc
index 36f09a7725f..d936ce3ade2 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/font_access/font_metadata.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -30,15 +29,8 @@ FontIterator::FontIterator(ExecutionContext* context)
ScriptPromise FontIterator::next(ScriptState* script_state) {
if (permission_status_ == PermissionStatus::ASK) {
if (!pending_resolver_) {
-#if defined(OS_MAC)
- remote_manager_->RequestPermission(WTF::Bind(
- &FontIterator::DidGetPermissionResponse, WrapWeakPersistent(this)));
- pending_resolver_ =
- MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-#else
remote_manager_->EnumerateLocalFonts(WTF::Bind(
&FontIterator::DidGetEnumerationResponse, WrapWeakPersistent(this)));
-#endif
pending_resolver_ =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
}
@@ -75,39 +67,26 @@ FontIteratorEntry* FontIterator::GetNextEntry() {
return result;
}
-void FontIterator::DidGetPermissionResponse(PermissionStatus status) {
- permission_status_ = status;
-
- if (permission_status_ != PermissionStatus::GRANTED) {
- pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kNotAllowedError, "Permission Error"));
- pending_resolver_.Clear();
- return;
- }
-
- FontCache* font_cache = FontCache::GetFontCache();
- auto metadata = font_cache->EnumerateAvailableFonts();
- for (const auto& entry : metadata) {
- entries_.push_back(FontMetadata::Create(entry));
- }
-
- pending_resolver_->Resolve(GetNextEntry());
- pending_resolver_.Clear();
-}
-
void FontIterator::DidGetEnumerationResponse(
FontEnumerationStatus status,
base::ReadOnlySharedMemoryRegion region) {
switch (status) {
+ case FontEnumerationStatus::kOk:
+ break;
case FontEnumerationStatus::kUnimplemented:
pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError,
"Not yet supported on this platform."));
pending_resolver_.Clear();
return;
- case FontEnumerationStatus::kUnexpectedError:
+ case FontEnumerationStatus::kNeedsUserActivation:
pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
- DOMExceptionCode::kUnknownError, "An unexpected error occured."));
+ DOMExceptionCode::kSecurityError, "User activation is required."));
+ pending_resolver_.Clear();
+ return;
+ case FontEnumerationStatus::kNotVisible:
+ pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kSecurityError, "Page needs to be visible."));
pending_resolver_.Clear();
return;
case FontEnumerationStatus::kPermissionDenied:
@@ -116,8 +95,12 @@ void FontIterator::DidGetEnumerationResponse(
DOMExceptionCode::kNotAllowedError, "Permission not granted."));
pending_resolver_.Clear();
return;
+ case FontEnumerationStatus::kUnexpectedError:
default:
- break;
+ pending_resolver_->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kUnknownError, "An unexpected error occured."));
+ pending_resolver_.Clear();
+ return;
}
permission_status_ = PermissionStatus::GRANTED;
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.h b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.h
index fee6fe73fbb..366951369bd 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.h
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.h
@@ -39,7 +39,6 @@ class FontIterator final : public ScriptWrappable,
private:
FontIteratorEntry* GetNextEntry();
- void DidGetPermissionResponse(PermissionStatus);
void DidGetEnumerationResponse(FontEnumerationStatus,
base::ReadOnlySharedMemoryRegion);
void ContextDestroyed() override;
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl
index 00a04b3df82..9a8536ab538 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_iterator.idl
@@ -8,7 +8,7 @@
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface
[
SecureContext,
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
RuntimeEnabled=FontAccess
] interface FontIterator {
[CallWith=ScriptState] Promise<any> next();
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_manager.cc b/chromium/third_party/blink/renderer/modules/font_access/font_manager.cc
index dffd5a252ee..725d3b6735b 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_manager.cc
@@ -26,7 +26,6 @@ void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
ScriptValue FontManager::query(ScriptState* script_state,
ExceptionState& exception_state) {
- ValidateRequest(ExecutionContext::From(script_state), exception_state);
if (exception_state.HadException())
return ScriptValue();
@@ -51,15 +50,4 @@ void FontManager::Trace(blink::Visitor* visitor) const {
ScriptWrappable::Trace(visitor);
}
-void FontManager::ValidateRequest(ExecutionContext* context,
- ExceptionState& exception_state) {
- DCHECK(context);
- auto* frame = To<LocalDOMWindow>(context)->GetFrame();
-
- if (!LocalFrame::HasTransientUserActivation(frame)) {
- exception_state.ThrowSecurityError(
- "Must be handling a user gesture to enumerate local fonts.");
- }
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_manager.h b/chromium/third_party/blink/renderer/modules/font_access/font_manager.h
index 36d2929dd2a..3448adc9b47 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_manager.h
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_manager.h
@@ -14,7 +14,6 @@ namespace blink {
class ScriptState;
class ScriptValue;
-class ExecutionContext;
class FontManager final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -25,9 +24,6 @@ class FontManager final : public ScriptWrappable {
DISALLOW_COPY_AND_ASSIGN(FontManager);
void Trace(blink::Visitor*) const override;
-
- private:
- void ValidateRequest(ExecutionContext*, ExceptionState&);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.h b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.h
index 7225efbc778..aab5474093c 100644
--- a/chromium/third_party/blink/renderer/modules/font_access/font_metadata.h
+++ b/chromium/third_party/blink/renderer/modules/font_access/font_metadata.h
@@ -14,7 +14,12 @@ namespace blink {
class ScriptState;
class ScriptPromise;
class ScriptPromiseResolver;
-struct FontEnumerationEntry;
+
+struct FontEnumerationEntry {
+ String postscript_name;
+ String full_name;
+ String family;
+};
class BLINK_EXPORT FontMetadata final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
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 99e2284cba4..94312f7edb3 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
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_HAPTIC_ACTUATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_HAPTIC_ACTUATOR_H_
+#include "device/gamepad/public/cpp/gamepad.h"
#include "device/gamepad/public/mojom/gamepad.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
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 24343d47bff..e093c7b4b93 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
+++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
@@ -24,7 +24,7 @@
*/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface GamepadList {
readonly attribute unsigned long length;
Gamepad item(optional unsigned long index = 0);
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 727095cd318..52232774cf4 100644
--- a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -28,10 +28,13 @@
#include "base/auto_reset.h"
#include "device/gamepad/public/cpp/gamepad_features.h"
#include "device/gamepad/public/cpp/gamepads.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#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/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/navigator.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/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -40,6 +43,7 @@
#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"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
@@ -75,6 +79,38 @@ NavigatorGamepad& NavigatorGamepad::From(Navigator& navigator) {
return *supplement;
}
+namespace {
+
+void RecordGamepadsForIdentifiabilityStudy(ExecutionContext* context,
+ GamepadList* gamepads) {
+ if (!context || !IdentifiabilityStudySettings::Get()->ShouldSample(
+ IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kWebFeature,
+ WebFeature::kGetGamepads)))
+ return;
+ IdentifiableTokenBuilder builder;
+ if (gamepads) {
+ for (unsigned i = 0; i < gamepads->length(); i++) {
+ if (auto* gp = gamepads->item(i)) {
+ builder.AddValue(gp->axes().size())
+ .AddValue(gp->buttons().size())
+ .AddValue(gp->connected())
+ .AddToken(IdentifiabilityBenignStringToken(gp->id()))
+ .AddToken(IdentifiabilityBenignStringToken(gp->mapping()))
+ .AddValue(gp->timestamp());
+ if (auto* vb = gp->vibrationActuator()) {
+ builder.AddToken(IdentifiabilityBenignStringToken(vb->type()));
+ }
+ }
+ }
+ }
+ IdentifiabilityMetricBuilder(context->UkmSourceID())
+ .SetWebfeature(WebFeature::kGetGamepads, builder.GetToken())
+ .Record(context->UkmRecorder());
+}
+
+} // namespace
+
// static
GamepadList* NavigatorGamepad::getGamepads(Navigator& navigator,
ExceptionState& exception_state) {
@@ -82,26 +118,56 @@ GamepadList* NavigatorGamepad::getGamepads(Navigator& navigator,
// Using an existing NavigatorGamepad if one exists, but don't create one
// for a detached window, as its subclasses depend on a non-null window.
auto* gamepad = Supplement<Navigator>::From<NavigatorGamepad>(navigator);
- return gamepad ? gamepad->Gamepads() : nullptr;
+ if (gamepad) {
+ auto* result = gamepad->Gamepads();
+ RecordGamepadsForIdentifiabilityStudy(gamepad->GetExecutionContext(),
+ result);
+ return result;
+ }
+ return nullptr;
}
auto* navigator_gamepad = &NavigatorGamepad::From(navigator);
- if (base::FeatureList::IsEnabled(features::kRestrictGamepadAccess)) {
- ExecutionContext* context = navigator_gamepad->GetExecutionContext();
- if (!context || !context->IsSecureContext()) {
+ ExecutionContext* context = navigator_gamepad->GetExecutionContext();
+ if (!context || !context->IsSecureContext()) {
+ if (base::FeatureList::IsEnabled(features::kRestrictGamepadAccess)) {
exception_state.ThrowSecurityError(kSecureContextBlocked);
return nullptr;
+ } else {
+ context->AddConsoleMessage(
+ MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "getGamepad will now require Secure Context. "
+ "Please update your application accordingly. "
+ "For more information see "
+ "https://github.com/w3c/gamepad/pull/120"),
+ /*discard_duplicates=*/true);
}
+ }
- if (!context->IsFeatureEnabled(
- mojom::blink::FeaturePolicyFeature::kGamepad)) {
+ if (!context->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kGamepad)) {
+ if (base::FeatureList::IsEnabled(features::kRestrictGamepadAccess)) {
exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
return nullptr;
+ } else {
+ context->AddConsoleMessage(
+ MakeGarbageCollected<ConsoleMessage>(
+ mojom::blink::ConsoleMessageSource::kJavaScript,
+ mojom::blink::ConsoleMessageLevel::kWarning,
+ "getGamepad will now require a Permission Policy. "
+ "Please update your application accordingly. "
+ "For more information see "
+ "https://github.com/w3c/gamepad/pull/112"),
+ /*discard_duplicates=*/true);
}
}
- return NavigatorGamepad::From(navigator).Gamepads();
+ auto* result = NavigatorGamepad::From(navigator).Gamepads();
+ RecordGamepadsForIdentifiabilityStudy(context, result);
+ return result;
}
GamepadList* NavigatorGamepad::Gamepads() {
diff --git a/chromium/third_party/blink/renderer/modules/hid/BUILD.gn b/chromium/third_party/blink/renderer/modules/hid/BUILD.gn
index 366ebb168ac..805fea0e881 100644
--- a/chromium/third_party/blink/renderer/modules/hid/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/hid/BUILD.gn
@@ -8,18 +8,12 @@ blink_modules_sources("hid") {
sources = [
"hid.cc",
"hid.h",
- "hid_collection_info.cc",
- "hid_collection_info.h",
"hid_connection_event.cc",
"hid_connection_event.h",
"hid_device.cc",
"hid_device.h",
"hid_input_report_event.cc",
"hid_input_report_event.h",
- "hid_report_info.cc",
- "hid_report_info.h",
- "hid_report_item.cc",
- "hid_report_item.h",
"navigator_hid.cc",
"navigator_hid.h",
]
@@ -27,7 +21,7 @@ blink_modules_sources("hid") {
source_set("unit_tests") {
testonly = true
- sources = [ "hid_report_item_test.cc" ]
+ sources = [ "hid_device_test.cc" ]
configs += [
"//third_party/blink/renderer:config",
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.cc b/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.cc
deleted file mode 100644
index f8851a5e86b..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/hid/hid_collection_info.h"
-
-#include "services/device/public/mojom/hid.mojom-blink.h"
-#include "third_party/blink/renderer/modules/hid/hid_report_info.h"
-
-namespace blink {
-
-HIDCollectionInfo::HIDCollectionInfo(
- const device::mojom::blink::HidCollectionInfo& info)
- : usage_page_(info.usage->usage_page),
- usage_(info.usage->usage),
- collection_type_(info.collection_type) {
- for (const auto& child : info.children)
- children_.push_back(MakeGarbageCollected<HIDCollectionInfo>(*child));
- for (const auto& report : info.input_reports)
- input_reports_.push_back(MakeGarbageCollected<HIDReportInfo>(*report));
- for (const auto& report : info.output_reports)
- output_reports_.push_back(MakeGarbageCollected<HIDReportInfo>(*report));
- for (const auto& report : info.feature_reports)
- feature_reports_.push_back(MakeGarbageCollected<HIDReportInfo>(*report));
-}
-
-HIDCollectionInfo::~HIDCollectionInfo() = default;
-
-uint16_t HIDCollectionInfo::usagePage() const {
- return usage_page_;
-}
-
-uint16_t HIDCollectionInfo::usage() const {
- return usage_;
-}
-
-const HeapVector<Member<HIDCollectionInfo>>& HIDCollectionInfo::children()
- const {
- return children_;
-}
-
-const HeapVector<Member<HIDReportInfo>>& HIDCollectionInfo::inputReports()
- const {
- return input_reports_;
-}
-
-const HeapVector<Member<HIDReportInfo>>& HIDCollectionInfo::outputReports()
- const {
- return output_reports_;
-}
-
-const HeapVector<Member<HIDReportInfo>>& HIDCollectionInfo::featureReports()
- const {
- return feature_reports_;
-}
-
-uint32_t HIDCollectionInfo::collectionType() const {
- return collection_type_;
-}
-
-void HIDCollectionInfo::Trace(Visitor* visitor) const {
- visitor->Trace(children_);
- visitor->Trace(input_reports_);
- visitor->Trace(output_reports_);
- visitor->Trace(feature_reports_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.h b/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.h
deleted file mode 100644
index 094fecf2860..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_COLLECTION_INFO_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_COLLECTION_INFO_H_
-
-#include "services/device/public/mojom/hid.mojom-blink-forward.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 HIDReportInfo;
-
-class MODULES_EXPORT HIDCollectionInfo : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit HIDCollectionInfo(
- const device::mojom::blink::HidCollectionInfo& collection);
- ~HIDCollectionInfo() override;
-
- uint16_t usagePage() const;
- uint16_t usage() const;
- const HeapVector<Member<HIDCollectionInfo>>& children() const;
- const HeapVector<Member<HIDReportInfo>>& inputReports() const;
- const HeapVector<Member<HIDReportInfo>>& outputReports() const;
- const HeapVector<Member<HIDReportInfo>>& featureReports() const;
- uint32_t collectionType() const;
-
- void Trace(Visitor* visitor) const override;
-
- private:
- uint16_t usage_page_;
- uint16_t usage_;
- uint32_t collection_type_;
- HeapVector<Member<HIDCollectionInfo>> children_;
- HeapVector<Member<HIDReportInfo>> input_reports_;
- HeapVector<Member<HIDReportInfo>> output_reports_;
- HeapVector<Member<HIDReportInfo>> feature_reports_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_COLLECTION_INFO_H_
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl b/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl
index 23fcf24ddd2..787d63e64df 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_collection_info.idl
@@ -5,24 +5,21 @@
// Information about a HID collection, including its reports and subcollections.
// https://wicg.github.io/webhid/index.html#report-descriptor
-[
- Exposed(Window WebHID),
- SecureContext
-] interface HIDCollectionInfo {
+dictionary HIDCollectionInfo {
// The 16-bit usage page associated with this collection. Zero if not set.
- readonly attribute unsigned short usagePage;
+ unsigned short usagePage;
// The 16-bit usage value associated with this collection. Zero if not set.
- readonly attribute unsigned short usage;
+ unsigned short usage;
// The subcollections of this collection, in the order they were encountered
// in the report descriptor.
- readonly attribute FrozenArray<HIDCollectionInfo> children;
+ sequence<HIDCollectionInfo> children;
// Input, output, and feature reports described in this collection, sorted
// by report ID. If this is a subcollection, only the portion of the report
// described within this collection is included.
- readonly attribute FrozenArray<HIDReportInfo> inputReports;
- readonly attribute FrozenArray<HIDReportInfo> outputReports;
- readonly attribute FrozenArray<HIDReportInfo> featureReports;
+ sequence<HIDReportInfo> inputReports;
+ sequence<HIDReportInfo> outputReports;
+ sequence<HIDReportInfo> featureReports;
};
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_device.cc b/chromium/third_party/blink/renderer/modules/hid/hid_device.cc
index 01dbcc3971c..51191c76b67 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_device.cc
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device.cc
@@ -6,13 +6,14 @@
#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/modules/v8/v8_hid_collection_info.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_hid_report_info.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/hid/hid.h"
-#include "third_party/blink/renderer/modules/hid/hid_collection_info.h"
#include "third_party/blink/renderer/modules/hid/hid_input_report_event.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -85,6 +86,129 @@ bool IsProtected(
return false;
}
+// The HID specification defines four canonical unit systems. Each unit system
+// corresponds to a set of units for length, mass, time, temperature, current,
+// and luminous intensity. The vendor-defined unit system can be used for
+// devices which produce measurements that cannot be adequately described by
+// these unit systems.
+//
+// See the Units table in section 6.2.2.7 of the Device Class Definition for
+// HID v1.11.
+// https://www.usb.org/document-library/device-class-definition-hid-111
+enum HidUnitSystem {
+ // none: No unit system
+ kUnitSystemNone = 0x00,
+ // si-linear: Centimeter, Gram, Seconds, Kelvin, Ampere, Candela
+ kUnitSystemSILinear = 0x01,
+ // si-rotation: Radians, Gram, Seconds, Kelvin, Ampere, Candela
+ kUnitSystemSIRotation = 0x02,
+ // english-linear: Inch, Slug, Seconds, Fahrenheit, Ampere, Candela
+ kUnitSystemEnglishLinear = 0x03,
+ // english-linear: Degrees, Slug, Seconds, Fahrenheit, Ampere, Candela
+ kUnitSystemEnglishRotation = 0x04,
+ // vendor-defined unit system
+ kUnitSystemVendorDefined = 0x0f,
+};
+
+uint32_t ConvertHidUsageAndPageToUint32(
+ const device::mojom::blink::HidUsageAndPage& usage) {
+ return (usage.usage_page) << 16 | usage.usage;
+}
+
+String UnitSystemToString(uint8_t unit) {
+ DCHECK_LE(unit, 0x0f);
+ switch (unit) {
+ case kUnitSystemNone:
+ return "none";
+ case kUnitSystemSILinear:
+ return "si-linear";
+ case kUnitSystemSIRotation:
+ return "si-rotation";
+ case kUnitSystemEnglishLinear:
+ return "english-linear";
+ case kUnitSystemEnglishRotation:
+ return "english-rotation";
+ case kUnitSystemVendorDefined:
+ return "vendor-defined";
+ default:
+ break;
+ }
+ // Values other than those defined in HidUnitSystem are reserved by the spec.
+ return "reserved";
+}
+
+// Convert |unit_factor_exponent| from its coded representation to a signed
+// integer type.
+int8_t UnitFactorExponentToInt(uint8_t unit_factor_exponent) {
+ DCHECK_LE(unit_factor_exponent, 0x0f);
+ // Values from 0x08 to 0x0f encode negative exponents.
+ if (unit_factor_exponent > 0x08)
+ return int8_t{unit_factor_exponent} - 16;
+ return unit_factor_exponent;
+}
+
+// Unpack the 32-bit unit definition value |unit| into each of its components.
+// The unit definition value includes the unit system as well as unit factor
+// exponents for each of the 6 units defined by the unit system.
+void UnpackUnitValues(uint32_t unit,
+ String& unit_system,
+ int8_t& length_exponent,
+ int8_t& mass_exponent,
+ int8_t& time_exponent,
+ int8_t& temperature_exponent,
+ int8_t& current_exponent,
+ int8_t& luminous_intensity_exponent) {
+ unit_system = UnitSystemToString(unit & 0x0f);
+ length_exponent = UnitFactorExponentToInt((unit >> 4) & 0x0f);
+ mass_exponent = UnitFactorExponentToInt((unit >> 8) & 0x0f);
+ time_exponent = UnitFactorExponentToInt((unit >> 12) & 0x0f);
+ temperature_exponent = UnitFactorExponentToInt((unit >> 16) & 0x0f);
+ current_exponent = UnitFactorExponentToInt((unit >> 20) & 0x0f);
+ luminous_intensity_exponent = UnitFactorExponentToInt((unit >> 24) & 0x0f);
+}
+
+HIDReportInfo* ToHIDReportInfo(
+ const device::mojom::blink::HidReportDescription& report_info) {
+ HIDReportInfo* result = HIDReportInfo::Create();
+ result->setReportId(report_info.report_id);
+
+ HeapVector<Member<HIDReportItem>> items;
+ for (const auto& item : report_info.items)
+ items.push_back(HIDDevice::ToHIDReportItem(*item));
+ result->setItems(items);
+
+ return result;
+}
+
+HIDCollectionInfo* ToHIDCollectionInfo(
+ const device::mojom::blink::HidCollectionInfo& collection) {
+ HIDCollectionInfo* result = HIDCollectionInfo::Create();
+ result->setUsage(collection.usage->usage);
+ result->setUsagePage(collection.usage->usage_page);
+
+ HeapVector<Member<HIDReportInfo>> input_reports;
+ for (const auto& report : collection.input_reports)
+ input_reports.push_back(ToHIDReportInfo(*report));
+ result->setInputReports(input_reports);
+
+ HeapVector<Member<HIDReportInfo>> output_reports;
+ for (const auto& report : collection.output_reports)
+ output_reports.push_back(ToHIDReportInfo(*report));
+ result->setOutputReports(output_reports);
+
+ HeapVector<Member<HIDReportInfo>> feature_reports;
+ for (const auto& report : collection.feature_reports)
+ feature_reports.push_back(ToHIDReportInfo(*report));
+ result->setFeatureReports(feature_reports);
+
+ HeapVector<Member<HIDCollectionInfo>> children;
+ for (const auto& child : collection.children)
+ children.push_back(ToHIDCollectionInfo(*child));
+ result->setChildren(children);
+
+ return result;
+}
+
} // namespace
HIDDevice::HIDDevice(HID* parent,
@@ -98,10 +222,8 @@ HIDDevice::HIDDevice(HID* parent,
DCHECK(device_info_);
for (const auto& collection : device_info_->collections) {
// Omit information about top-level collections with protected usages.
- if (!IsProtected(*collection->usage)) {
- collections_.push_back(
- MakeGarbageCollected<HIDCollectionInfo>(*collection));
- }
+ if (!IsProtected(*collection->usage))
+ collections_.push_back(ToHIDCollectionInfo(*collection));
}
}
@@ -373,4 +495,57 @@ void HIDDevice::MarkRequestComplete(ScriptPromiseResolver* resolver) {
device_requests_.erase(find_result);
}
+// static
+HIDReportItem* HIDDevice::ToHIDReportItem(
+ const device::mojom::blink::HidReportItem& report_item) {
+ HIDReportItem* result = HIDReportItem::Create();
+ result->setIsAbsolute(!report_item.is_relative);
+ result->setIsArray(!report_item.is_variable);
+ result->setIsRange(report_item.is_range);
+ result->setHasNull(report_item.has_null_position);
+ result->setReportSize(report_item.report_size);
+ result->setReportCount(report_item.report_count);
+ result->setUnitExponent(
+ UnitFactorExponentToInt(report_item.unit_exponent & 0x0f));
+ result->setLogicalMinimum(report_item.logical_minimum);
+ result->setLogicalMaximum(report_item.logical_maximum);
+ result->setPhysicalMinimum(report_item.physical_minimum);
+ result->setPhysicalMaximum(report_item.physical_maximum);
+
+ Vector<uint32_t> usages;
+ for (const auto& usage : report_item.usages)
+ usages.push_back(ConvertHidUsageAndPageToUint32(*usage));
+ result->setUsages(usages);
+
+ result->setUsageMinimum(
+ ConvertHidUsageAndPageToUint32(*report_item.usage_minimum));
+ result->setUsageMaximum(
+ ConvertHidUsageAndPageToUint32(*report_item.usage_maximum));
+
+ String unit_system;
+ int8_t unit_factor_length_exponent;
+ int8_t unit_factor_mass_exponent;
+ int8_t unit_factor_time_exponent;
+ int8_t unit_factor_temperature_exponent;
+ int8_t unit_factor_current_exponent;
+ int8_t unit_factor_luminous_intensity_exponent;
+ UnpackUnitValues(report_item.unit, unit_system, unit_factor_length_exponent,
+ unit_factor_mass_exponent, unit_factor_time_exponent,
+ unit_factor_temperature_exponent,
+ unit_factor_current_exponent,
+ unit_factor_luminous_intensity_exponent);
+ result->setUnitSystem(unit_system);
+ result->setUnitFactorLengthExponent(unit_factor_length_exponent);
+ result->setUnitFactorMassExponent(unit_factor_mass_exponent);
+ result->setUnitFactorTimeExponent(unit_factor_time_exponent);
+ result->setUnitFactorTemperatureExponent(unit_factor_temperature_exponent);
+ result->setUnitFactorCurrentExponent(unit_factor_current_exponent);
+ result->setUnitFactorLuminousIntensityExponent(
+ unit_factor_luminous_intensity_exponent);
+
+ // TODO(mattreynolds): Set |strings_|.
+
+ return result;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_device.h b/chromium/third_party/blink/renderer/modules/hid/hid_device.h
index 5a7bab92a5b..24b338e9bd2 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_device.h
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device.h
@@ -10,6 +10,7 @@
#include "third_party/blink/public/mojom/hid/hid.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_hid_report_item.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
@@ -70,6 +71,9 @@ class MODULES_EXPORT HIDDevice
// ExecutionContextLifecycleObserver:
void ContextDestroyed() override;
+ static HIDReportItem* ToHIDReportItem(
+ const device::mojom::blink::HidReportItem& report_item);
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_item_test.cc b/chromium/third_party/blink/renderer/modules/hid/hid_device_test.cc
index 6902ab2ac50..ae9d383d662 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_item_test.cc
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_device_test.cc
@@ -1,8 +1,8 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "third_party/blink/renderer/modules/hid/hid_report_item.h"
+#include "third_party/blink/renderer/modules/hid/hid_device.h"
#include "services/device/public/mojom/hid.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -61,38 +61,38 @@ device::mojom::blink::HidReportItemPtr MakeReportItem() {
} // namespace
-TEST(HIDReportItemTest, singleUsageItem) {
+TEST(HIDDeviceTest, singleUsageItem) {
device::mojom::blink::HidReportItemPtr mojo_item = MakeReportItem();
- HIDReportItem item(*mojo_item);
+ HIDReportItem* item = HIDDevice::ToHIDReportItem(*mojo_item);
// Check that all item properties are correctly converted for the sample
// report item.
- EXPECT_TRUE(item.isAbsolute());
- EXPECT_FALSE(item.isArray());
- EXPECT_FALSE(item.isRange());
- EXPECT_FALSE(item.hasNull());
- EXPECT_EQ(1U, item.usages().size());
- EXPECT_EQ(0x00090001U, item.usages()[0]);
- EXPECT_EQ(0U, item.usageMinimum());
- EXPECT_EQ(0U, item.usageMaximum());
- EXPECT_TRUE(item.strings().IsEmpty());
- EXPECT_EQ(8U, item.reportSize());
- EXPECT_EQ(1U, item.reportCount());
- EXPECT_EQ(0, item.unitExponent());
- EXPECT_EQ("none", item.unitSystem());
- EXPECT_EQ(0, item.unitFactorLengthExponent());
- EXPECT_EQ(0, item.unitFactorMassExponent());
- EXPECT_EQ(0, item.unitFactorTimeExponent());
- EXPECT_EQ(0, item.unitFactorTemperatureExponent());
- EXPECT_EQ(0, item.unitFactorCurrentExponent());
- EXPECT_EQ(0, item.unitFactorLuminousIntensityExponent());
- EXPECT_EQ(0, item.logicalMinimum());
- EXPECT_EQ(1, item.logicalMaximum());
- EXPECT_EQ(0, item.physicalMinimum());
- EXPECT_EQ(1, item.physicalMaximum());
+ EXPECT_TRUE(item->isAbsolute());
+ EXPECT_FALSE(item->isArray());
+ EXPECT_FALSE(item->isRange());
+ EXPECT_FALSE(item->hasNull());
+ EXPECT_EQ(1U, item->usages().size());
+ EXPECT_EQ(0x00090001U, item->usages()[0]);
+ EXPECT_EQ(0U, item->usageMinimum());
+ EXPECT_EQ(0U, item->usageMaximum());
+ EXPECT_FALSE(item->hasStrings());
+ EXPECT_EQ(8U, item->reportSize());
+ EXPECT_EQ(1U, item->reportCount());
+ EXPECT_EQ(0, item->unitExponent());
+ EXPECT_EQ("none", item->unitSystem());
+ EXPECT_EQ(0, item->unitFactorLengthExponent());
+ EXPECT_EQ(0, item->unitFactorMassExponent());
+ EXPECT_EQ(0, item->unitFactorTimeExponent());
+ EXPECT_EQ(0, item->unitFactorTemperatureExponent());
+ EXPECT_EQ(0, item->unitFactorCurrentExponent());
+ EXPECT_EQ(0, item->unitFactorLuminousIntensityExponent());
+ EXPECT_EQ(0, item->logicalMinimum());
+ EXPECT_EQ(1, item->logicalMaximum());
+ EXPECT_EQ(0, item->physicalMinimum());
+ EXPECT_EQ(1, item->physicalMaximum());
}
-TEST(HIDReportItemTest, multiUsageItem) {
+TEST(HIDDeviceTest, multiUsageItem) {
device::mojom::blink::HidReportItemPtr mojo_item = MakeReportItem();
// Configure the item to use 8 non-consecutive usages.
@@ -103,22 +103,22 @@ TEST(HIDReportItemTest, multiUsageItem) {
}
mojo_item->report_size = 1; // 1 bit.
mojo_item->report_count = 8;
- HIDReportItem item(*mojo_item);
-
- EXPECT_EQ(8U, item.usages().size());
- EXPECT_EQ(0x00090002U, item.usages()[0]);
- EXPECT_EQ(0x00090004U, item.usages()[1]);
- EXPECT_EQ(0x00090006U, item.usages()[2]);
- EXPECT_EQ(0x00090008U, item.usages()[3]);
- EXPECT_EQ(0x0009000aU, item.usages()[4]);
- EXPECT_EQ(0x0009000cU, item.usages()[5]);
- EXPECT_EQ(0x0009000eU, item.usages()[6]);
- EXPECT_EQ(0x00090010U, item.usages()[7]);
- EXPECT_EQ(1U, item.reportSize());
- EXPECT_EQ(8U, item.reportCount());
+ HIDReportItem* item = HIDDevice::ToHIDReportItem(*mojo_item);
+
+ EXPECT_EQ(8U, item->usages().size());
+ EXPECT_EQ(0x00090002U, item->usages()[0]);
+ EXPECT_EQ(0x00090004U, item->usages()[1]);
+ EXPECT_EQ(0x00090006U, item->usages()[2]);
+ EXPECT_EQ(0x00090008U, item->usages()[3]);
+ EXPECT_EQ(0x0009000aU, item->usages()[4]);
+ EXPECT_EQ(0x0009000cU, item->usages()[5]);
+ EXPECT_EQ(0x0009000eU, item->usages()[6]);
+ EXPECT_EQ(0x00090010U, item->usages()[7]);
+ EXPECT_EQ(1U, item->reportSize());
+ EXPECT_EQ(8U, item->reportCount());
}
-TEST(HIDReportItemTest, usageRangeItem) {
+TEST(HIDDeviceTest, usageRangeItem) {
device::mojom::blink::HidReportItemPtr mojo_item = MakeReportItem();
// Configure the item to use a usage range. The item defines eight fields,
@@ -131,32 +131,32 @@ TEST(HIDReportItemTest, usageRangeItem) {
mojo_item->usage_maximum->usage = 0x08; // 8th button usage.
mojo_item->report_size = 1; // 1 bit.
mojo_item->report_count = 8;
- HIDReportItem item(*mojo_item);
+ HIDReportItem* item = HIDDevice::ToHIDReportItem(*mojo_item);
- EXPECT_TRUE(item.usages().IsEmpty());
- EXPECT_EQ(0x00090001U, item.usageMinimum());
- EXPECT_EQ(0x00090008U, item.usageMaximum());
- EXPECT_EQ(1U, item.reportSize());
- EXPECT_EQ(8U, item.reportCount());
+ EXPECT_FALSE(item->hasStrings());
+ EXPECT_EQ(0x00090001U, item->usageMinimum());
+ EXPECT_EQ(0x00090008U, item->usageMaximum());
+ EXPECT_EQ(1U, item->reportSize());
+ EXPECT_EQ(8U, item->reportCount());
}
-TEST(HIDReportItemTest, unitDefinition) {
+TEST(HIDDeviceTest, unitDefinition) {
device::mojom::blink::HidReportItemPtr mojo_item = MakeReportItem();
// Add a unit definition and check that the unit properties are correctly
// converted.
mojo_item->unit_exponent = 0x0C; // 10^-4
mojo_item->unit = 0x0000E111; // g*cm/s^2
- HIDReportItem item(*mojo_item);
-
- EXPECT_EQ("si-linear", item.unitSystem());
- EXPECT_EQ(-4, item.unitExponent());
- EXPECT_EQ(1, item.unitFactorLengthExponent());
- EXPECT_EQ(1, item.unitFactorMassExponent());
- EXPECT_EQ(-2, item.unitFactorTimeExponent());
- EXPECT_EQ(0, item.unitFactorTemperatureExponent());
- EXPECT_EQ(0, item.unitFactorCurrentExponent());
- EXPECT_EQ(0, item.unitFactorLuminousIntensityExponent());
+ HIDReportItem* item = HIDDevice::ToHIDReportItem(*mojo_item);
+
+ EXPECT_EQ("si-linear", item->unitSystem());
+ EXPECT_EQ(-4, item->unitExponent());
+ EXPECT_EQ(1, item->unitFactorLengthExponent());
+ EXPECT_EQ(1, item->unitFactorMassExponent());
+ EXPECT_EQ(-2, item->unitFactorTimeExponent());
+ EXPECT_EQ(0, item->unitFactorTemperatureExponent());
+ EXPECT_EQ(0, item->unitFactorCurrentExponent());
+ EXPECT_EQ(0, item->unitFactorLuminousIntensityExponent());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.cc b/chromium/third_party/blink/renderer/modules/hid/hid_report_info.cc
deleted file mode 100644
index 0e39ccb9b96..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/hid/hid_report_info.h"
-
-#include "services/device/public/mojom/hid.mojom-blink.h"
-#include "third_party/blink/renderer/modules/hid/hid_report_item.h"
-
-namespace blink {
-
-HIDReportInfo::HIDReportInfo(
- const device::mojom::blink::HidReportDescription& report)
- : report_id_(report.report_id) {
- for (const auto& item : report.items)
- items_.push_back(MakeGarbageCollected<HIDReportItem>(*item));
-}
-
-HIDReportInfo::~HIDReportInfo() {}
-
-uint8_t HIDReportInfo::reportId() const {
- return report_id_;
-}
-
-const HeapVector<Member<HIDReportItem>>& HIDReportInfo::items() const {
- return items_;
-}
-
-void HIDReportInfo::Trace(Visitor* visitor) const {
- visitor->Trace(items_);
- ScriptWrappable::Trace(visitor);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.h b/chromium/third_party/blink/renderer/modules/hid/hid_report_info.h
deleted file mode 100644
index dbdfb69bff7..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_INFO_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_INFO_H_
-
-#include "services/device/public/mojom/hid.mojom-blink-forward.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 HIDReportItem;
-
-class MODULES_EXPORT HIDReportInfo : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit HIDReportInfo(
- const device::mojom::blink::HidReportDescription& report);
- ~HIDReportInfo() override;
-
- uint8_t reportId() const;
- const HeapVector<Member<HIDReportItem>>& items() const;
-
- void Trace(Visitor* visitor) const override;
-
- private:
- uint8_t report_id_;
- HeapVector<Member<HIDReportItem>> items_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_INFO_H_
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.idl b/chromium/third_party/blink/renderer/modules/hid/hid_report_info.idl
index 0270175af99..c6fe2c612d1 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_info.idl
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_report_info.idl
@@ -8,13 +8,10 @@
// only the portion of the report contained by the collection.
// https://wicg.github.io/webhid/index.html#report-descriptor
-[
- Exposed(Window WebHID),
- SecureContext
-] interface HIDReportInfo {
+dictionary HIDReportInfo {
// The 8-bit report ID associated with this report.
- readonly attribute octet reportId;
+ octet reportId;
// An ordered array that describes the fields within this report.
- readonly attribute FrozenArray<HIDReportItem> items;
+ sequence<HIDReportItem> items;
};
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.cc b/chromium/third_party/blink/renderer/modules/hid/hid_report_item.cc
deleted file mode 100644
index 514b4c2f0aa..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/hid/hid_report_item.h"
-
-#include "services/device/public/mojom/hid.mojom-blink.h"
-
-namespace blink {
-
-namespace {
-
-// The HID specification defines four canonical unit systems. Each unit system
-// corresponds to a set of units for length, mass, time, temperature, current,
-// and luminous intensity. The vendor-defined unit system can be used for
-// devices which produce measurements that cannot be adequately described by
-// these unit systems.
-//
-// See the Units table in section 6.2.2.7 of the Device Class Definition for
-// HID v1.11.
-// https://www.usb.org/document-library/device-class-definition-hid-111
-enum HidUnitSystem {
- // none: No unit system
- kUnitSystemNone = 0x00,
- // si-linear: Centimeter, Gram, Seconds, Kelvin, Ampere, Candela
- kUnitSystemSILinear = 0x01,
- // si-rotation: Radians, Gram, Seconds, Kelvin, Ampere, Candela
- kUnitSystemSIRotation = 0x02,
- // english-linear: Inch, Slug, Seconds, Fahrenheit, Ampere, Candela
- kUnitSystemEnglishLinear = 0x03,
- // english-linear: Degrees, Slug, Seconds, Fahrenheit, Ampere, Candela
- kUnitSystemEnglishRotation = 0x04,
- // vendor-defined unit system
- kUnitSystemVendorDefined = 0x0f,
-};
-
-uint32_t ConvertHidUsageAndPageToUint32(
- const device::mojom::blink::HidUsageAndPage& usage) {
- return (usage.usage_page) << 16 | usage.usage;
-}
-
-String UnitSystemToString(uint8_t unit) {
- DCHECK_LE(unit, 0x0f);
- switch (unit) {
- case kUnitSystemNone:
- return "none";
- case kUnitSystemSILinear:
- return "si-linear";
- case kUnitSystemSIRotation:
- return "si-rotation";
- case kUnitSystemEnglishLinear:
- return "english-linear";
- case kUnitSystemEnglishRotation:
- return "english-rotation";
- case kUnitSystemVendorDefined:
- return "vendor-defined";
- default:
- break;
- }
- // Values other than those defined in HidUnitSystem are reserved by the spec.
- return "reserved";
-}
-
-// Convert |unit_factor_exponent| from its coded representation to a signed
-// integer type.
-int8_t UnitFactorExponentToInt(uint8_t unit_factor_exponent) {
- DCHECK_LE(unit_factor_exponent, 0x0f);
- // Values from 0x08 to 0x0f encode negative exponents.
- if (unit_factor_exponent > 0x08)
- return int8_t{unit_factor_exponent} - 16;
- return unit_factor_exponent;
-}
-
-// Unpack the 32-bit unit definition value |unit| into each of its components.
-// The unit definition value includes the unit system as well as unit factor
-// exponents for each of the 6 units defined by the unit system.
-void UnpackUnitValues(uint32_t unit,
- String& unit_system,
- int8_t& length_exponent,
- int8_t& mass_exponent,
- int8_t& time_exponent,
- int8_t& temperature_exponent,
- int8_t& current_exponent,
- int8_t& luminous_intensity_exponent) {
- unit_system = UnitSystemToString(unit & 0x0f);
- length_exponent = UnitFactorExponentToInt((unit >> 4) & 0x0f);
- mass_exponent = UnitFactorExponentToInt((unit >> 8) & 0x0f);
- time_exponent = UnitFactorExponentToInt((unit >> 12) & 0x0f);
- temperature_exponent = UnitFactorExponentToInt((unit >> 16) & 0x0f);
- current_exponent = UnitFactorExponentToInt((unit >> 20) & 0x0f);
- luminous_intensity_exponent = UnitFactorExponentToInt((unit >> 24) & 0x0f);
-}
-
-} // namespace
-
-HIDReportItem::HIDReportItem(const device::mojom::blink::HidReportItem& item)
- : is_absolute_(!item.is_relative),
- is_array_(!item.is_variable),
- is_range_(item.is_range),
- has_null_(item.has_null_position),
- report_size_(item.report_size),
- report_count_(item.report_count),
- unit_exponent_(UnitFactorExponentToInt(item.unit_exponent & 0x0f)),
- logical_minimum_(item.logical_minimum),
- logical_maximum_(item.logical_maximum),
- physical_minimum_(item.physical_minimum),
- physical_maximum_(item.physical_maximum) {
- for (const auto& usage : item.usages)
- usages_.push_back(ConvertHidUsageAndPageToUint32(*usage));
- usage_minimum_ = ConvertHidUsageAndPageToUint32(*item.usage_minimum);
- usage_maximum_ = ConvertHidUsageAndPageToUint32(*item.usage_maximum);
- UnpackUnitValues(item.unit, unit_system_, unit_factor_length_exponent_,
- unit_factor_mass_exponent_, unit_factor_time_exponent_,
- unit_factor_temperature_exponent_,
- unit_factor_current_exponent_,
- unit_factor_luminous_intensity_exponent_);
-
- // TODO(mattreynolds): Set |strings_|.
-}
-
-HIDReportItem::~HIDReportItem() = default;
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.h b/chromium/third_party/blink/renderer/modules/hid/hid_report_item.h
deleted file mode 100644
index 223e351a906..00000000000
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_ITEM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_ITEM_H_
-
-#include "services/device/public/mojom/hid.mojom-blink-forward.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"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class MODULES_EXPORT HIDReportItem : public ScriptWrappable {
- DEFINE_WRAPPERTYPEINFO();
-
- public:
- explicit HIDReportItem(const device::mojom::blink::HidReportItem& item);
- ~HIDReportItem() override;
-
- bool isAbsolute() const { return is_absolute_; }
- bool isArray() const { return is_array_; }
- bool isRange() const { return is_range_; }
- bool hasNull() const { return has_null_; }
- const Vector<uint32_t>& usages() const { return usages_; }
- uint32_t usageMinimum() const { return usage_minimum_; }
- uint32_t usageMaximum() const { return usage_maximum_; }
- const Vector<String>& strings() const { return strings_; }
- uint16_t reportSize() const { return report_size_; }
- uint16_t reportCount() const { return report_count_; }
- int8_t unitExponent() const { return unit_exponent_; }
- String unitSystem() const { return unit_system_; }
- int8_t unitFactorLengthExponent() const {
- return unit_factor_length_exponent_;
- }
- int8_t unitFactorMassExponent() const { return unit_factor_mass_exponent_; }
- int8_t unitFactorTimeExponent() const { return unit_factor_time_exponent_; }
- int8_t unitFactorTemperatureExponent() const {
- return unit_factor_temperature_exponent_;
- }
- int8_t unitFactorCurrentExponent() const {
- return unit_factor_current_exponent_;
- }
- int8_t unitFactorLuminousIntensityExponent() const {
- return unit_factor_luminous_intensity_exponent_;
- }
- int32_t logicalMinimum() const { return logical_minimum_; }
- int32_t logicalMaximum() const { return logical_maximum_; }
- int32_t physicalMinimum() const { return physical_minimum_; }
- int32_t physicalMaximum() const { return physical_maximum_; }
-
- private:
- bool is_absolute_;
- bool is_array_;
- bool is_range_;
- bool has_null_;
- Vector<uint32_t> usages_;
- Vector<String> strings_;
- uint32_t usage_minimum_;
- uint32_t usage_maximum_;
- uint16_t report_size_;
- uint16_t report_count_;
- int8_t unit_exponent_;
- String unit_system_;
- int8_t unit_factor_length_exponent_;
- int8_t unit_factor_mass_exponent_;
- int8_t unit_factor_time_exponent_;
- int8_t unit_factor_temperature_exponent_;
- int8_t unit_factor_current_exponent_;
- int8_t unit_factor_luminous_intensity_exponent_;
- int32_t logical_minimum_;
- int32_t logical_maximum_;
- int32_t physical_minimum_;
- int32_t physical_maximum_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_HID_HID_REPORT_ITEM_H_
diff --git a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl b/chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl
index eed3732738d..01ee6d86e96 100644
--- a/chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl
+++ b/chromium/third_party/blink/renderer/modules/hid/hid_report_item.idl
@@ -28,77 +28,74 @@ enum HIDUnitSystem {
"reserved",
};
-[
- Exposed(Window WebHID),
- SecureContext
-] interface HIDReportItem {
+dictionary HIDReportItem {
// True if the item represents an absolute measurement (e.g. joystick tilt)
// or false if it represents a relative measurement (e.g. mouse movement).
- readonly attribute boolean isAbsolute;
+ boolean isAbsolute;
// True if the item is an Array or false if it is a Variable. Array items
// are typically used when a device needs to represent a large number of
// button-type inputs, but only a few inputs need to be active at once.
// Variable items require space in the report for each input, but can report
// all inputs simultaneously.
- readonly attribute boolean isArray;
+ boolean isArray;
// True if the usages for this item are defined by |usageMinimum| and
// |usageMaximum| or false if the usages are defined by |usages|.
- readonly attribute boolean isRange;
+ boolean isRange;
// True if the item uses an out-of-bounds value when there is no input.
- readonly attribute boolean hasNull;
+ boolean hasNull;
// An ordered list of 32-bit usage values associated with this item. Unused
// if |isRange| is true. If |reportCount| is two or more, usages are
// assigned from the list until the list is exhausted.
- readonly attribute FrozenArray<unsigned long> usages;
+ sequence<unsigned long> usages;
// The minimum and maximum usage values associated with this item. Unused if
// |isRange| is false. If |reportCount| is two or more, usages are assigned
// starting from |usageMinimum| and increment by one.
- readonly attribute unsigned long usageMinimum;
- readonly attribute unsigned long usageMaximum;
+ unsigned long usageMinimum;
+ unsigned long usageMaximum;
// The size of a single field described by this item, in bits.
- readonly attribute unsigned short reportSize;
+ unsigned short reportSize;
// The number of similar fields described by this item. The total size of
// the item described by this report is |reportSize| * |reportCount| bits.
- readonly attribute unsigned short reportCount;
+ unsigned short reportCount;
// The base 10 exponent of the units for this report item. For instance, for
// kilograms |unitExponent| would be 3 and for micrograms it would be -6.
- readonly attribute byte unitExponent;
+ byte unitExponent;
// The unit system determines which units are used for length, mass, time,
// temperature, current, and luminous intensity. May be "none" if the values
// for this report item are unitless.
- readonly attribute HIDUnitSystem unitSystem;
+ HIDUnitSystem unitSystem;
// The following members determine the exponents for each factor of the
// unit definition. For instance, for acceleration all factors would have
// an exponent of 0 except |unitFactorLengthExponent| which would be 1 and
// |unitFactorTimeExponent| which would be -2.
- readonly attribute byte unitFactorLengthExponent;
- readonly attribute byte unitFactorMassExponent;
- readonly attribute byte unitFactorTimeExponent;
- readonly attribute byte unitFactorTemperatureExponent;
- readonly attribute byte unitFactorCurrentExponent;
- readonly attribute byte unitFactorLuminousIntensityExponent;
+ byte unitFactorLengthExponent;
+ byte unitFactorMassExponent;
+ byte unitFactorTimeExponent;
+ byte unitFactorTemperatureExponent;
+ byte unitFactorCurrentExponent;
+ byte unitFactorLuminousIntensityExponent;
// The minimum and maximum values that may be represented by this input. A
// device with |hasNull| may report a value outside this range to indicate
// no input.
- readonly attribute long logicalMinimum;
- readonly attribute long logicalMaximum;
+ long logicalMinimum;
+ long logicalMaximum;
// The minimum and maximum values, scaled to the units described by |unit|
// and |unitExponent|.
- readonly attribute long physicalMinimum;
- readonly attribute long physicalMaximum;
+ long physicalMinimum;
+ long physicalMaximum;
// The strings associated with this item.
- readonly attribute FrozenArray<DOMString> strings;
+ sequence<DOMString> strings;
};
diff --git a/chromium/third_party/blink/renderer/modules/hid/idls.gni b/chromium/third_party/blink/renderer/modules/hid/idls.gni
index 2291d2fff3e..0ef4e76abcf 100644
--- a/chromium/third_party/blink/renderer/modules/hid/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/hid/idls.gni
@@ -4,18 +4,18 @@
modules_idl_files = [
"hid.idl",
- "hid_collection_info.idl",
"hid_connection_event.idl",
"hid_device.idl",
"hid_input_report_event.idl",
- "hid_report_info.idl",
- "hid_report_item.idl",
]
modules_dictionary_idl_files = [
+ "hid_collection_info.idl",
"hid_connection_event_init.idl",
"hid_device_filter.idl",
"hid_device_request_options.idl",
+ "hid_report_info.idl",
+ "hid_report_item.idl",
]
modules_dependency_idl_files = [ "navigator_hid.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/idle/BUILD.gn b/chromium/third_party/blink/renderer/modules/idle/BUILD.gn
index 65836c24807..b5e9abb1e21 100644
--- a/chromium/third_party/blink/renderer/modules/idle/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/idle/BUILD.gn
@@ -8,5 +8,9 @@ blink_modules_sources("idle") {
sources = [
"idle_detector.cc",
"idle_detector.h",
+ "idle_manager.cc",
+ "idle_manager.h",
]
+
+ deps = [ "//third_party/blink/renderer/modules/permissions" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/idle/DEPS b/chromium/third_party/blink/renderer/modules/idle/DEPS
index e9d07a53c45..8964ea2c731 100644
--- a/chromium/third_party/blink/renderer/modules/idle/DEPS
+++ b/chromium/third_party/blink/renderer/modules/idle/DEPS
@@ -3,5 +3,6 @@ include_rules = [
"+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/permissions/permission_utils.h",
"+third_party/blink/renderer/modules/idle",
]
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc b/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc
index 8dafda3126f..ecc231cb906 100644
--- a/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -8,7 +8,6 @@
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_idle_options.h"
@@ -16,11 +15,11 @@
#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/execution_context/security_context.h"
+#include "third_party/blink/renderer/modules/idle/idle_manager.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/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
-
namespace blink {
namespace {
@@ -41,9 +40,7 @@ IdleDetector* IdleDetector::Create(ScriptState* script_state) {
}
IdleDetector::IdleDetector(ExecutionContext* context)
- : ExecutionContextClient(context),
- receiver_(this, context),
- idle_service_(context) {}
+ : ExecutionContextClient(context), receiver_(this, context) {}
IdleDetector::~IdleDetector() = default;
@@ -85,6 +82,17 @@ String IdleDetector::screenState() const {
}
}
+// static
+ScriptPromise IdleDetector::requestPermission(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ if (!script_state->ContextIsValid())
+ return ScriptPromise();
+
+ auto* context = ExecutionContext::From(script_state);
+ return IdleManager::From(context)->RequestPermission(script_state,
+ exception_state);
+}
+
ScriptPromise IdleDetector::start(ScriptState* script_state,
const IdleOptions* options,
ExceptionState& exception_state) {
@@ -128,21 +136,16 @@ ScriptPromise IdleDetector::start(ScriptState* script_state,
// See https://bit.ly/2S0zRAS for task types.
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
-
- if (!idle_service_.is_bound()) {
- GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
- idle_service_.BindNewPipeAndPassReceiver(task_runner));
- idle_service_.set_disconnect_handler(WTF::Bind(
- &IdleDetector::OnServiceDisconnected, WrapWeakPersistent(this)));
- }
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI);
mojo::PendingRemote<mojom::blink::IdleMonitor> remote;
receiver_.Bind(remote.InitWithNewPipeAndPassReceiver(), task_runner);
+ receiver_.set_disconnect_handler(WTF::Bind(
+ &IdleDetector::OnMonitorDisconnected, WrapWeakPersistent(this)));
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
- idle_service_->AddMonitor(
+ IdleManager::From(context)->AddMonitor(
threshold_, std::move(remote),
WTF::Bind(&IdleDetector::OnAddMonitor, WrapWeakPersistent(this),
WrapPersistent(resolver)));
@@ -161,18 +164,16 @@ void IdleDetector::Abort(AbortSignal* signal) {
resolver_ = nullptr;
}
- idle_service_.reset();
receiver_.reset();
}
-void IdleDetector::OnServiceDisconnected() {
+void IdleDetector::OnMonitorDisconnected() {
if (resolver_) {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError, "Idle detection not available."));
resolver_ = nullptr;
}
- idle_service_.reset();
receiver_.reset();
}
@@ -183,7 +184,7 @@ void IdleDetector::OnAddMonitor(ScriptPromiseResolver* resolver,
case IdleManagerError::kPermissionDisabled:
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError,
- "Notification permission disabled"));
+ "Idle detection permission denied"));
break;
case IdleManagerError::kSuccess:
DCHECK(state);
@@ -212,7 +213,6 @@ void IdleDetector::Trace(Visitor* visitor) const {
visitor->Trace(signal_);
visitor->Trace(resolver_);
visitor->Trace(receiver_);
- visitor->Trace(idle_service_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextClient::Trace(visitor);
ActiveScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_detector.h b/chromium/third_party/blink/renderer/modules/idle/idle_detector.h
index d2e3c707585..ccc6d65e1c2 100644
--- a/chromium/third_party/blink/renderer/modules/idle/idle_detector.h
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_detector.h
@@ -50,6 +50,7 @@ class IdleDetector final : public EventTargetWithInlineData,
// IdleDetector IDL interface.
String userState() const;
String screenState() const;
+ static ScriptPromise requestPermission(ScriptState*, ExceptionState&);
ScriptPromise start(ScriptState*, const IdleOptions*, ExceptionState&);
DEFINE_ATTRIBUTE_EVENT_LISTENER(change, kChange)
@@ -61,7 +62,7 @@ class IdleDetector final : public EventTargetWithInlineData,
void Update(mojom::blink::IdleStatePtr state) override;
void Abort(AbortSignal*);
- void OnServiceDisconnected();
+ void OnMonitorDisconnected();
void OnAddMonitor(ScriptPromiseResolver*,
mojom::blink::IdleManagerError,
mojom::blink::IdleStatePtr);
@@ -78,9 +79,6 @@ class IdleDetector final : public EventTargetWithInlineData,
IdleDetector,
HeapMojoWrapperMode::kWithoutContextObserver>
receiver_;
- HeapMojoRemote<mojom::blink::IdleManager,
- HeapMojoWrapperMode::kWithoutContextObserver>
- idle_service_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/idle/idle_detector.idl b/chromium/third_party/blink/renderer/modules/idle/idle_detector.idl
index fcff94f42ba..e582e0ca4f1 100644
--- a/chromium/third_party/blink/renderer/modules/idle/idle_detector.idl
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_detector.idl
@@ -24,5 +24,6 @@ enum ScreenIdleState {
readonly attribute UserIdleState? userState;
readonly attribute ScreenIdleState? screenState;
attribute EventHandler onchange;
+ [Exposed=Window, CallWith=ScriptState, RaisesException, MeasureAs=IdleDetectionPermissionRequested] static Promise<PermissionState> requestPermission();
[CallWith=ScriptState, RaisesException, MeasureAs=IdleDetectionStart] Promise<void> start(optional IdleOptions options = {});
};
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..3710156ce61
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_manager.cc
@@ -0,0 +1,110 @@
+// Copyright 2020 The Chromium Authors. 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 "third_party/blink/public/common/browser_interface_broker_proxy.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/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+// static
+const char IdleManager::kSupplementName[] = "IdleManager";
+
+// static
+IdleManager* IdleManager::From(ExecutionContext* context) {
+ DCHECK(context);
+ DCHECK(context->IsContextThread());
+
+ IdleManager* manager =
+ Supplement<ExecutionContext>::From<IdleManager>(context);
+ if (!manager) {
+ manager = MakeGarbageCollected<IdleManager>(context);
+ Supplement<ExecutionContext>::ProvideTo(*context, manager);
+ }
+
+ return manager;
+}
+
+IdleManager::IdleManager(ExecutionContext* context)
+ : Supplement<ExecutionContext>(*context),
+ idle_service_(context),
+ permission_service_(context) {}
+
+IdleManager::~IdleManager() = default;
+
+ScriptPromise IdleManager::RequestPermission(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ ExecutionContext* context = GetSupplementable();
+ DCHECK_EQ(context, ExecutionContext::From(script_state));
+
+ // This function is annotated with [Exposed=Window].
+ DCHECK(context->IsWindow());
+ auto* window = To<LocalDOMWindow>(context);
+
+ if (!LocalFrame::HasTransientUserActivation(window->GetFrame())) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotAllowedError,
+ "Must be handling a user gesture to show a permission request.");
+ return ScriptPromise();
+ }
+
+ // This interface is annotated with [SecureContext].
+ DCHECK(context->IsSecureContext());
+
+ if (!permission_service_.is_bound()) {
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ ConnectToPermissionService(
+ context,
+ permission_service_.BindNewPipeAndPassReceiver(std::move(task_runner)));
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ ScriptPromise promise = resolver->Promise();
+
+ permission_service_->RequestPermission(
+ CreatePermissionDescriptor(mojom::blink::PermissionName::IDLE_DETECTION),
+ LocalFrame::HasTransientUserActivation(window->GetFrame()),
+ WTF::Bind(&IdleManager::OnPermissionRequestComplete, WrapPersistent(this),
+ WrapPersistent(resolver)));
+ return promise;
+}
+
+void IdleManager::AddMonitor(
+ base::TimeDelta threshold,
+ mojo::PendingRemote<mojom::blink::IdleMonitor> monitor,
+ mojom::blink::IdleManager::AddMonitorCallback callback) {
+ if (!idle_service_.is_bound()) {
+ ExecutionContext* context = GetSupplementable();
+ // See https://bit.ly/2S0zRAS for task types.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ context->GetTaskRunner(TaskType::kMiscPlatformAPI);
+ context->GetBrowserInterfaceBroker().GetInterface(
+ idle_service_.BindNewPipeAndPassReceiver(task_runner));
+ }
+
+ idle_service_->AddMonitor(threshold, std::move(monitor), std::move(callback));
+}
+
+void IdleManager::Trace(Visitor* visitor) const {
+ visitor->Trace(idle_service_);
+ visitor->Trace(permission_service_);
+ Supplement<ExecutionContext>::Trace(visitor);
+}
+
+void IdleManager::OnPermissionRequestComplete(
+ ScriptPromiseResolver* resolver,
+ mojom::blink::PermissionStatus status) {
+ resolver->Resolve(PermissionStatusToString(status));
+}
+
+} // 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..66c22c751c4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/idle/idle_manager.h
@@ -0,0 +1,53 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
+
+#include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ExceptionState;
+class ExecutionContext;
+class ScriptPromise;
+class ScriptPromiseResolver;
+class ScriptState;
+
+class IdleManager final : public GarbageCollected<IdleManager>,
+ public Supplement<ExecutionContext> {
+ public:
+ static const char kSupplementName[];
+
+ static IdleManager* From(ExecutionContext*);
+
+ explicit IdleManager(ExecutionContext*);
+ ~IdleManager();
+
+ ScriptPromise RequestPermission(ScriptState*, ExceptionState&);
+ void AddMonitor(base::TimeDelta threshold,
+ mojo::PendingRemote<mojom::blink::IdleMonitor>,
+ mojom::blink::IdleManager::AddMonitorCallback);
+
+ void Trace(Visitor*) const override;
+
+ private:
+ void OnPermissionRequestComplete(ScriptPromiseResolver*,
+ mojom::blink::PermissionStatus);
+
+ HeapMojoRemote<mojom::blink::IdleManager,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ idle_service_;
+ HeapMojoRemote<mojom::blink::PermissionService,
+ HeapMojoWrapperMode::kWithoutContextObserver>
+ permission_service_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_IDLE_IDLE_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h b/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h
index 90326b00710..c9b134d8955 100644
--- a/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h
+++ b/chromium/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h
@@ -94,7 +94,7 @@ class ImageDownloaderImpl final : public GarbageCollected<ImageDownloaderImpl>,
HeapMojoReceiver<mojom::blink::ImageDownloader,
ImageDownloaderImpl,
- HeapMojoWrapperMode::kWithoutContextObserver>
+ HeapMojoWrapperMode::kForceWithoutContextObserver>
receiver_;
DISALLOW_COPY_AND_ASSIGN(ImageDownloaderImpl);
diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/BUILD.gn b/chromium/third_party/blink/renderer/modules/imagecapture/BUILD.gn
index 57f67a85513..deb9de1f70b 100644
--- a/chromium/third_party/blink/renderer/modules/imagecapture/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/imagecapture/BUILD.gn
@@ -16,6 +16,7 @@ blink_modules_sources("imagecapture") {
"//media",
"//media/capture/mojom:image_capture_blink",
"//skia",
+ "//third_party/blink/renderer/modules/permissions:permissions",
"//third_party/libyuv",
]
}
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 febb37a1018..4294805e393 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -268,7 +268,7 @@ ScriptPromise IDBFactory::GetDatabaseInfo(ScriptState* script_state,
return resolver->Promise();
}
- if (!CachedAllowIndexedDB(script_state)) {
+ if (!AllowIndexedDB(script_state)) {
exception_state.ThrowDOMException(DOMExceptionCode::kUnknownError,
kPermissionDeniedErrorMessage);
resolver->Reject();
@@ -304,7 +304,7 @@ IDBRequest* IDBFactory::GetDatabaseNames(ScriptState* script_state,
WebFeature::kFileAccessedDatabase);
}
- if (!CachedAllowIndexedDB(script_state)) {
+ if (!AllowIndexedDB(script_state)) {
request->HandleResponse(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
return request;
@@ -365,7 +365,7 @@ IDBOpenDBRequest* IDBFactory::OpenInternal(ScriptState* script_state,
script_state, database_callbacks, std::move(transaction_backend),
transaction_id, version, std::move(metrics), GetObservedFeature());
- if (!CachedAllowIndexedDB(script_state)) {
+ if (!AllowIndexedDB(script_state)) {
request->HandleResponse(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
return request;
@@ -436,7 +436,7 @@ IDBOpenDBRequest* IDBFactory::DeleteDatabaseInternal(
IDBDatabaseMetadata::kDefaultVersion, std::move(metrics),
GetObservedFeature());
- if (!CachedAllowIndexedDB(script_state)) {
+ if (!AllowIndexedDB(script_state)) {
request->HandleResponse(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
return request;
@@ -491,7 +491,8 @@ bool IDBFactory::AllowIndexedDB(ScriptState* script_state) {
return false;
if (auto* settings_client = frame->GetContentSettingsClient()) {
// This triggers a sync IPC.
- return settings_client->AllowIndexedDB();
+ return settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kIndexedDB);
}
return true;
}
@@ -501,15 +502,8 @@ bool IDBFactory::AllowIndexedDB(ScriptState* script_state) {
if (!content_settings_client)
return true;
// This triggers a sync IPC.
- return content_settings_client->AllowIndexedDB();
-}
-
-bool IDBFactory::CachedAllowIndexedDB(ScriptState* script_state) {
- if (!cached_allowed_.has_value()) {
- // Cache the AllowIndexedDB() call because it triggers a sync IPC.
- cached_allowed_.emplace(AllowIndexedDB(script_state));
- }
- return cached_allowed_.value();
+ return content_settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kIndexedDB);
}
mojo::PendingAssociatedRemote<mojom::blink::IDBCallbacks>
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 f38a013411d..0299fa661ce 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.h
@@ -95,7 +95,6 @@ class MODULES_EXPORT IDBFactory final : public ScriptWrappable {
bool);
bool AllowIndexedDB(ScriptState* script_state);
- bool CachedAllowIndexedDB(ScriptState* script_state);
mojo::PendingAssociatedRemote<mojom::blink::IDBCallbacks> GetCallbacksProxy(
std::unique_ptr<WebIDBCallbacks> callbacks);
@@ -107,8 +106,6 @@ class MODULES_EXPORT IDBFactory final : public ScriptWrappable {
mojo::Remote<mojom::blink::IDBFactory> factory_;
mojo::Remote<mojom::blink::FeatureObserver> feature_observer_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- base::Optional<bool> cached_allowed_;
};
} // namespace blink
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 8e432325bfb..b44b4989edc 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_observation.h
@@ -17,6 +17,7 @@ namespace blink {
class IDBAny;
class IDBKeyRange;
+class IDBValue;
class ScriptState;
class IDBObservation final : public ScriptWrappable {
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 212bd13b97a..99d9c2f463b 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
@@ -412,7 +412,7 @@ TEST_F(IDBRequestTest, ConnectionsAfterStopping) {
mojo::AssociatedRemote<mojom::blink::IDBDatabase> remote;
std::unique_ptr<BackendDatabaseWithMockedClose> mock_database =
std::make_unique<BackendDatabaseWithMockedClose>(
- remote.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ remote.BindNewEndpointAndPassDedicatedReceiver());
EXPECT_CALL(*mock_database, Close()).Times(1);
auto transaction_backend = std::make_unique<MockWebIDBTransaction>(
@@ -435,7 +435,7 @@ TEST_F(IDBRequestTest, ConnectionsAfterStopping) {
mojo::AssociatedRemote<mojom::blink::IDBDatabase> remote;
std::unique_ptr<BackendDatabaseWithMockedClose> mock_database =
std::make_unique<BackendDatabaseWithMockedClose>(
- remote.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ remote.BindNewEndpointAndPassDedicatedReceiver());
EXPECT_CALL(*mock_database, Close()).Times(1);
auto transaction_backend = std::make_unique<MockWebIDBTransaction>(
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 2abce1b4708..0fafc4435e1 100644
--- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
+++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_transfer_token.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink-forward.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink-forward.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"
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 cd970ca15dc..5b60db8bd50 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
@@ -81,66 +81,65 @@ bool StructTraits<blink::mojom::IDBIndexMetadataDataView,
}
// static
-blink::mojom::IDBKeyDataDataView::Tag
-UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+blink::mojom::IDBKeyDataView::Tag
+UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
GetTag(const std::unique_ptr<blink::IDBKey>& key) {
DCHECK(key.get());
switch (key->GetType()) {
case blink::mojom::IDBKeyType::Array:
- return blink::mojom::IDBKeyDataDataView::Tag::KEY_ARRAY;
+ return blink::mojom::IDBKeyDataView::Tag::KEY_ARRAY;
case blink::mojom::IDBKeyType::Binary:
- return blink::mojom::IDBKeyDataDataView::Tag::BINARY;
+ return blink::mojom::IDBKeyDataView::Tag::BINARY;
case blink::mojom::IDBKeyType::String:
- return blink::mojom::IDBKeyDataDataView::Tag::STRING;
+ return blink::mojom::IDBKeyDataView::Tag::STRING;
case blink::mojom::IDBKeyType::Date:
- return blink::mojom::IDBKeyDataDataView::Tag::DATE;
+ return blink::mojom::IDBKeyDataView::Tag::DATE;
case blink::mojom::IDBKeyType::Number:
- return blink::mojom::IDBKeyDataDataView::Tag::NUMBER;
+ return blink::mojom::IDBKeyDataView::Tag::NUMBER;
case blink::mojom::IDBKeyType::None:
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER_NONE;
+ return blink::mojom::IDBKeyDataView::Tag::OTHER_NONE;
// Not used, fall through to NOTREACHED.
case blink::mojom::IDBKeyType::Invalid: // Only used in blink.
case blink::mojom::IDBKeyType::Min:; // Only used in the browser.
}
NOTREACHED();
- return blink::mojom::IDBKeyDataDataView::Tag::OTHER_NONE;
+ return blink::mojom::IDBKeyDataView::Tag::OTHER_NONE;
}
// static
-bool UnionTraits<
- blink::mojom::IDBKeyDataDataView,
- std::unique_ptr<blink::IDBKey>>::Read(blink::mojom::IDBKeyDataDataView data,
- std::unique_ptr<blink::IDBKey>* out) {
+bool UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
+ Read(blink::mojom::IDBKeyDataView data,
+ std::unique_ptr<blink::IDBKey>* out) {
switch (data.tag()) {
- case blink::mojom::IDBKeyDataDataView::Tag::KEY_ARRAY: {
+ case blink::mojom::IDBKeyDataView::Tag::KEY_ARRAY: {
Vector<std::unique_ptr<blink::IDBKey>> array;
if (!data.ReadKeyArray(&array))
return false;
*out = blink::IDBKey::CreateArray(std::move(array));
return true;
}
- case blink::mojom::IDBKeyDataDataView::Tag::BINARY: {
+ case blink::mojom::IDBKeyDataView::Tag::BINARY: {
ArrayDataView<uint8_t> bytes;
data.GetBinaryDataView(&bytes);
*out = blink::IDBKey::CreateBinary(SharedBuffer::Create(
reinterpret_cast<const char*>(bytes.data()), bytes.size()));
return true;
}
- case blink::mojom::IDBKeyDataDataView::Tag::STRING: {
+ case blink::mojom::IDBKeyDataView::Tag::STRING: {
String string;
if (!data.ReadString(&string))
return false;
*out = blink::IDBKey::CreateString(String(string));
return true;
}
- case blink::mojom::IDBKeyDataDataView::Tag::DATE:
+ case blink::mojom::IDBKeyDataView::Tag::DATE:
*out = blink::IDBKey::CreateDate(data.date());
return true;
- case blink::mojom::IDBKeyDataDataView::Tag::NUMBER:
+ case blink::mojom::IDBKeyDataView::Tag::NUMBER:
*out = blink::IDBKey::CreateNumber(data.number());
return true;
- case blink::mojom::IDBKeyDataDataView::Tag::OTHER_NONE:
+ case blink::mojom::IDBKeyDataView::Tag::OTHER_NONE:
*out = blink::IDBKey::CreateNone();
return true;
}
@@ -150,34 +149,19 @@ bool UnionTraits<
// static
const Vector<std::unique_ptr<blink::IDBKey>>&
-UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
key_array(const std::unique_ptr<blink::IDBKey>& key) {
return key->Array();
}
// static
Vector<uint8_t>
-UnionTraits<blink::mojom::IDBKeyDataDataView, std::unique_ptr<blink::IDBKey>>::
+UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>>::
binary(const std::unique_ptr<blink::IDBKey>& key) {
return key->Binary()->CopyAs<Vector<uint8_t>>();
}
// static
-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,
- 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) {
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 4512701146b..8dcf25fe54c 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
@@ -87,11 +87,11 @@ struct MODULES_EXPORT StructTraits<blink::mojom::IDBIndexMetadataDataView,
};
template <>
-struct MODULES_EXPORT UnionTraits<blink::mojom::IDBKeyDataDataView,
- std::unique_ptr<blink::IDBKey>> {
- static blink::mojom::IDBKeyDataDataView::Tag GetTag(
+struct MODULES_EXPORT
+ UnionTraits<blink::mojom::IDBKeyDataView, std::unique_ptr<blink::IDBKey>> {
+ static blink::mojom::IDBKeyDataView::Tag GetTag(
const std::unique_ptr<blink::IDBKey>& key);
- static bool Read(blink::mojom::IDBKeyDataDataView data,
+ static bool Read(blink::mojom::IDBKeyDataView data,
std::unique_ptr<blink::IDBKey>* out);
static const Vector<std::unique_ptr<blink::IDBKey>>& key_array(
const std::unique_ptr<blink::IDBKey>& key);
@@ -117,15 +117,6 @@ struct MODULES_EXPORT UnionTraits<blink::mojom::IDBKeyDataDataView,
};
template <>
-struct MODULES_EXPORT
- 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::IDBValueDataView,
std::unique_ptr<blink::IDBValue>> {
static Vector<uint8_t> bits(const std::unique_ptr<blink::IDBValue>& input);
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 a56104c7297..26480f8f0a2 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
@@ -115,7 +115,7 @@ class WebIDBCursorImplTest : public testing::Test {
WebIDBCursorImplTest() : null_key_(IDBKey::CreateNone()) {
mojo::AssociatedRemote<mojom::blink::IDBCursor> remote;
mock_cursor_ = std::make_unique<MockCursorImpl>(
- remote.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ remote.BindNewEndpointAndPassDedicatedReceiver());
cursor_ = std::make_unique<WebIDBCursorImpl>(
remote.Unbind(), 1,
blink::scheduler::GetSingleThreadTaskRunnerForTesting());
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 d6717d40636..4c8146e869f 100644
--- a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
+++ b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
@@ -5,6 +5,10 @@
#include "third_party/blink/renderer/modules/keyboard/keyboard_layout.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.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"
@@ -14,6 +18,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -29,6 +34,31 @@ constexpr char kKeyboardMapChildFrameErrorMsg[] =
constexpr char kKeyboardMapRequestFailedErrorMsg[] =
"getLayoutMap() request could not be completed.";
+constexpr IdentifiableSurface kGetKeyboardLayoutMapSurface =
+ IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kWebFeature,
+ WebFeature::kKeyboardApiGetLayoutMap);
+
+IdentifiableToken ComputeLayoutValue(
+ const WTF::HashMap<WTF::String, WTF::String>& layout_map) {
+ IdentifiableTokenBuilder builder;
+ for (const auto& kv : layout_map) {
+ builder.AddToken(IdentifiabilityBenignStringToken(kv.key));
+ builder.AddToken(IdentifiabilityBenignStringToken(kv.value));
+ }
+ return builder.GetToken();
+}
+
+void RecordGetLayoutMapResult(ExecutionContext* context,
+ IdentifiableToken value) {
+ if (!context)
+ return;
+
+ IdentifiabilityMetricBuilder(context->UkmSourceID())
+ .Set(kGetKeyboardLayoutMapSurface, value)
+ .Record(context->UkmRecorder());
+}
+
} // namespace
KeyboardLayout::KeyboardLayout(ExecutionContext* context)
@@ -56,6 +86,12 @@ ScriptPromise KeyboardLayout::GetKeyboardLayoutMap(
}
if (!EnsureServiceConnected()) {
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ kGetKeyboardLayoutMapSurface)) {
+ RecordGetLayoutMapResult(ExecutionContext::From(script_state),
+ IdentifiableToken());
+ }
+
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kKeyboardMapRequestFailedErrorMsg);
return ScriptPromise();
@@ -101,12 +137,22 @@ void KeyboardLayout::GotKeyboardLayoutMap(
mojom::blink::GetKeyboardLayoutMapResultPtr result) {
DCHECK(script_promise_resolver_);
+ bool instrumentation_on = IdentifiabilityStudySettings::Get()->ShouldSample(
+ kGetKeyboardLayoutMapSurface);
+
switch (result->status) {
case mojom::blink::GetKeyboardLayoutMapStatus::kSuccess:
+ if (instrumentation_on) {
+ RecordGetLayoutMapResult(GetExecutionContext(),
+ ComputeLayoutValue(result->layout_map));
+ }
script_promise_resolver_->Resolve(
MakeGarbageCollected<KeyboardLayoutMap>(result->layout_map));
break;
case mojom::blink::GetKeyboardLayoutMapStatus::kFail:
+ if (instrumentation_on)
+ RecordGetLayoutMapResult(GetExecutionContext(), IdentifiableToken());
+
script_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kInvalidStateError,
kKeyboardMapRequestFailedErrorMsg));
diff --git a/chromium/third_party/blink/renderer/modules/launch/BUILD.gn b/chromium/third_party/blink/renderer/modules/launch/BUILD.gn
index d8fdf3f46ba..a057db9b89f 100644
--- a/chromium/third_party/blink/renderer/modules/launch/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/launch/BUILD.gn
@@ -19,7 +19,7 @@ blink_modules_sources("launch") {
]
deps = [
+ "//third_party/blink/renderer/modules/file_system_access",
"//third_party/blink/renderer/modules/filesystem",
- "//third_party/blink/renderer/modules/native_file_system",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc b/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc
index 17959aae866..66877449367 100644
--- a/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc
@@ -5,8 +5,8 @@
#include "third_party/blink/renderer/modules/launch/dom_window_launch_queue.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/modules/launch/launch_params.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/chromium/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc b/chromium/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
index bc06aee39ea..a33c74dc8c9 100644
--- a/chromium/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/file_handling_expiry_impl.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.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/origin_trials/origin_trial_context.h"
diff --git a/chromium/third_party/blink/renderer/modules/launch/launch_params.cc b/chromium/third_party/blink/renderer/modules/launch/launch_params.cc
index a02768ab8ee..02d232563c9 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_params.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_params.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/modules/launch/launch_params.h"
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/launch/launch_params.h b/chromium/third_party/blink/renderer/modules/launch/launch_params.h
index eac86d952c6..e3b60d539c3 100644
--- a/chromium/third_party/blink/renderer/modules/launch/launch_params.h
+++ b/chromium/third_party/blink/renderer/modules/launch/launch_params.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_PARAMS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_PARAMS_H_
-#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
+#include "third_party/blink/renderer/modules/file_system_access/native_file_system_handle.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
diff --git a/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc b/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc
index 4cc99255613..37ed2dacbe8 100644
--- a/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink.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/script/script.h"
diff --git a/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h b/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h
index 99d81a9a62e..7bcfbb54e50 100644
--- a/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h
+++ b/chromium/third_party/blink/renderer/modules/launch/web_launch_service_impl.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_WEB_LAUNCH_SERVICE_IMPL_H_
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
-#include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/native_file_system_directory_handle.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/web_launch/web_launch.mojom-blink.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
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 39efb80c60e..1bd532ef979 100644
--- a/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -448,7 +448,8 @@ bool LockManager::AllowLocks(ScriptState* script_state) {
cached_allowed_ = false;
} else if (auto* settings_client = frame->GetContentSettingsClient()) {
// This triggers a sync IPC.
- cached_allowed_ = settings_client->AllowWebLocks();
+ cached_allowed_ = settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kWebLocks);
} else {
cached_allowed_ = true;
}
@@ -459,7 +460,8 @@ bool LockManager::AllowLocks(ScriptState* script_state) {
cached_allowed_ = true;
} else {
// This triggers a sync IPC.
- cached_allowed_ = content_settings_client->AllowWebLocks();
+ cached_allowed_ = content_settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kWebLocks);
}
}
}
diff --git a/chromium/third_party/blink/renderer/modules/manifest/BUILD.gn b/chromium/third_party/blink/renderer/modules/manifest/BUILD.gn
index c4376853015..104612cc165 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/manifest/BUILD.gn
@@ -21,4 +21,6 @@ blink_modules_sources("manifest") {
"manifest_uma_util.cc",
"manifest_uma_util.h",
]
+
+ deps = [ "//third_party/blink/renderer/modules/navigatorcontentutils:navigatorcontentutils" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index 207c7b3c46b..d50f50ca92f 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -152,7 +152,7 @@ base::Optional<String> ManifestParser::ParseString(const JSONObject* object,
return base::nullopt;
String value;
- if (!json_value->AsString(&value)) {
+ if (!json_value->AsString(&value) || value.IsNull()) {
AddErrorInfo("property '" + key + "' ignored, type " + "string expected.");
return base::nullopt;
}
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
index e09876dd43f..d21d386b076 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/optional.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
@@ -537,6 +537,8 @@ TEST_F(ManifestParserTest, DisplayParseRules) {
}
TEST_F(ManifestParserTest, DisplayOverrideParseRules) {
+ ScopedWebAppManifestDisplayOverrideForTest display_override(true);
+
// Smoke test: if no display_override, no value.
{
auto& manifest = ParseManifest("{ \"display_override\": [] }");
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc b/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
index 5b7c0967506..ab790e1ce31 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
@@ -22,14 +22,11 @@ TypeConverter<blink::Manifest, blink::mojom::blink::ManifestPtr>::Convert(
if (input.is_null())
return output;
- if (!input->name.IsEmpty()) {
- output.name = base::NullableString16(blink::WebString(input->name).Utf16());
- }
+ if (!input->name.IsEmpty())
+ output.name = blink::WebString(input->name).Utf16();
- if (!input->short_name.IsEmpty()) {
- output.short_name =
- base::NullableString16(blink::WebString(input->short_name).Utf16());
- }
+ if (!input->short_name.IsEmpty())
+ output.short_name = blink::WebString(input->short_name).Utf16();
if (!input->start_url.IsEmpty())
output.start_url = input->start_url;
@@ -71,8 +68,7 @@ TypeConverter<blink::Manifest, blink::mojom::blink::ManifestPtr>::Convert(
output.background_color = input->background_color;
if (!input->gcm_sender_id.IsEmpty()) {
- output.gcm_sender_id =
- base::NullableString16(blink::WebString(input->gcm_sender_id).Utf16());
+ output.gcm_sender_id = blink::WebString(input->gcm_sender_id).Utf16();
}
if (!input->scope.IsEmpty())
@@ -119,13 +115,11 @@ TypeConverter<blink::Manifest::ShortcutItem,
output.name = blink::WebString(input->name).Utf16();
if (!input->short_name.IsEmpty()) {
- output.short_name =
- base::NullableString16(blink::WebString(input->short_name).Utf16());
+ output.short_name = blink::WebString(input->short_name).Utf16();
}
if (!input->description.IsEmpty()) {
- output.description =
- base::NullableString16(blink::WebString(input->description).Utf16());
+ output.description = blink::WebString(input->description).Utf16();
}
output.url = input->url;
@@ -177,15 +171,14 @@ TypeConverter<blink::Manifest::ShareTargetParams,
return output;
if (!input->title.IsEmpty()) {
- output.title =
- base::NullableString16(blink::WebString(input->title).Utf16());
+ output.title = blink::WebString(input->title).Utf16();
}
if (!input->text.IsEmpty())
- output.text = base::NullableString16(blink::WebString(input->text).Utf16());
+ output.text = blink::WebString(input->text).Utf16();
if (!input->url.IsEmpty())
- output.url = base::NullableString16(blink::WebString(input->url).Utf16());
+ output.url = blink::WebString(input->url).Utf16();
if (input->files.has_value()) {
for (auto& file : *input->files)
@@ -251,15 +244,14 @@ TypeConverter<blink::Manifest::RelatedApplication,
return output;
if (!input->platform.IsEmpty()) {
- output.platform =
- base::NullableString16(blink::WebString(input->platform).Utf16());
+ output.platform = blink::WebString(input->platform).Utf16();
}
if (input->url.has_value())
output.url = *input->url;
if (!input->id.IsEmpty())
- output.id = base::NullableString16(blink::WebString(input->id).Utf16());
+ output.id = blink::WebString(input->id).Utf16();
return output;
}
diff --git a/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters_unittest.cc b/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters_unittest.cc
index 6bcb873bd5e..e82992dbd8d 100644
--- a/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters_unittest.cc
+++ b/chromium/third_party/blink/renderer/modules/manifest/manifest_type_converters_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/manifest/manifest_type_converters.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h"
@@ -102,8 +103,7 @@ TEST_F(ManifestTypeConvertersTest, BasicShortcutIsCorrectlyConverted) {
ASSERT_EQ(manifest.shortcuts.size(), 1u);
EXPECT_TRUE(base::EqualsASCII(manifest.shortcuts[0].name, "name"));
- EXPECT_TRUE(base::EqualsASCII(manifest.shortcuts[0].short_name.string(),
- "short_name"));
+ EXPECT_EQ(manifest.shortcuts[0].short_name, base::ASCIIToUTF16("short_name"));
EXPECT_EQ(manifest.shortcuts[0].url.spec(), "http://example.com/url");
ASSERT_EQ(manifest.shortcuts[0].icons.size(), 1u);
diff --git a/chromium/third_party/blink/renderer/modules/media/BUILD.gn b/chromium/third_party/blink/renderer/modules/media/BUILD.gn
index 142e76900e4..77ea92275ef 100644
--- a/chromium/third_party/blink/renderer/modules/media/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/media/BUILD.gn
@@ -5,5 +5,27 @@
import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("media") {
- sources = [ "webmediaplayer_util.cc" ]
+ sources = [
+ "audio/audio_renderer_mixer_manager.cc",
+ "audio/audio_renderer_mixer_manager.h",
+ "audio/audio_renderer_sink_cache.cc",
+ "audio/audio_renderer_sink_cache.h",
+ "audio/mojo_audio_input_ipc.cc",
+ "audio/mojo_audio_input_ipc.h",
+ "audio/mojo_audio_output_ipc.cc",
+ "audio/mojo_audio_output_ipc.h",
+ "audio/web_audio_device_factory.cc",
+ "audio/web_audio_input_ipc_factory.cc",
+ "audio/web_audio_output_ipc_factory.cc",
+ "webmediaplayer_util.cc",
+ ]
+
+ if (is_fuchsia) {
+ sources += [ "audio/fuchsia_audio_device_factory.cc" ]
+
+ deps = [
+ "//media/fuchsia/audio",
+ "//media/fuchsia/mojom:mojom_blink",
+ ]
+ }
}
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/DEPS b/chromium/third_party/blink/renderer/modules/media/audio/DEPS
new file mode 100644
index 00000000000..a8cbd488aa6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/DEPS
@@ -0,0 +1,29 @@
+include_rules = [
+ "+base/unguessable_token.h",
+ "+base/threading/platform_thread.h",
+ "+media/audio",
+ "+media/base",
+ "+media/mojo",
+
+ # TODO(https://crbug.com/787252): Replace this use by a Blink singleton
+ # construction.
+ "+base/no_destructor.h",
+
+ # TODO(https://crbug.com/787252): Replace the use by WTF::HashMap.
+ "+base/containers/flat_map.h",
+]
+
+specific_include_rules = {
+ ".*test\.cc" : [
+ "+base/message_loop/message_pump_type.h",
+ "+base/run_loop.h",
+ "+base/test/bind_test_util.h",
+ "+base/test/gtest_util.h",
+ "+base/test/test_mock_time_task_runner.h",
+ "+base/threading/thread.h",
+ ],
+ "fuchsia_audio_device_factory\.cc" : [
+ "+media/fuchsia/audio/fuchsia_audio_capturer_source.h",
+ "+media/fuchsia/mojom",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.cc b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.cc
new file mode 100644
index 00000000000..81d39d5f406
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.cc
@@ -0,0 +1,250 @@
+// 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/renderer/modules/media/audio/audio_renderer_mixer_manager.h"
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_renderer_mixer.h"
+#include "media/base/audio_renderer_mixer_input.h"
+#include "third_party/blink/public/web/modules/media/audio/web_audio_device_factory.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace {
+
+// Calculate mixer output parameters based on mixer input parameters and
+// hardware parameters for audio output.
+media::AudioParameters GetMixerOutputParams(
+ const media::AudioParameters& input_params,
+ const media::AudioParameters& hardware_params,
+ media::AudioLatency::LatencyType latency) {
+ // For a compressed bitstream, no audio post processing is allowed, hence the
+ // output parameters should be the same as input parameters.
+ if (input_params.IsBitstreamFormat())
+ return input_params;
+
+ int output_sample_rate, preferred_output_buffer_size;
+ if (!hardware_params.IsValid() ||
+ hardware_params.format() == media::AudioParameters::AUDIO_FAKE) {
+ // With fake or invalid hardware params, don't waste cycles on resampling.
+ output_sample_rate = input_params.sample_rate();
+ preferred_output_buffer_size = 0; // Let media::AudioLatency() choose.
+ } else if (media::AudioLatency::IsResamplingPassthroughSupported(latency)) {
+ // Certain platforms don't require us to resample to a single rate for low
+ // latency, so again, don't waste cycles on resampling.
+ output_sample_rate = input_params.sample_rate();
+
+ // For playback, prefer the input params buffer size unless the hardware
+ // needs something even larger (say for Bluetooth devices).
+ if (latency == media::AudioLatency::LATENCY_PLAYBACK) {
+ preferred_output_buffer_size =
+ std::max(input_params.frames_per_buffer(),
+ hardware_params.frames_per_buffer());
+ } else {
+ preferred_output_buffer_size = hardware_params.frames_per_buffer();
+ }
+ } else {
+ // Otherwise, always resample and rebuffer to the hardware parameters.
+ output_sample_rate = hardware_params.sample_rate();
+ preferred_output_buffer_size = hardware_params.frames_per_buffer();
+ }
+
+ int output_buffer_size = 0;
+
+ // Adjust output buffer size according to the latency requirement.
+ switch (latency) {
+ case media::AudioLatency::LATENCY_INTERACTIVE:
+ output_buffer_size = media::AudioLatency::GetInteractiveBufferSize(
+ hardware_params.frames_per_buffer());
+ break;
+ case media::AudioLatency::LATENCY_RTC:
+ output_buffer_size = media::AudioLatency::GetRtcBufferSize(
+ output_sample_rate, preferred_output_buffer_size);
+ break;
+ case media::AudioLatency::LATENCY_PLAYBACK:
+ output_buffer_size = media::AudioLatency::GetHighLatencyBufferSize(
+ output_sample_rate, preferred_output_buffer_size);
+ break;
+ case media::AudioLatency::LATENCY_EXACT_MS:
+ // TODO(olka): add support when WebAudio requires it.
+ default:
+ NOTREACHED();
+ }
+
+ DCHECK_NE(output_buffer_size, 0);
+
+ media::AudioParameters params(input_params.format(),
+ input_params.channel_layout(),
+ output_sample_rate, output_buffer_size);
+
+ // Use the actual channel count when the channel layout is "DISCRETE".
+ if (input_params.channel_layout() == media::CHANNEL_LAYOUT_DISCRETE)
+ params.set_channels_for_discrete(input_params.channels());
+
+ // Specify the effects info the passed to the browser side.
+ params.set_effects(input_params.effects());
+
+ // Specify the latency info to be passed to the browser side.
+ params.set_latency_tag(latency);
+ return params;
+}
+
+} // namespace
+
+namespace blink {
+
+AudioRendererMixerManager::AudioRendererMixerManager(
+ CreateSinkCB create_sink_cb)
+ : create_sink_cb_(std::move(create_sink_cb)) {
+ DCHECK(create_sink_cb_);
+}
+
+AudioRendererMixerManager::~AudioRendererMixerManager() {
+ // References to AudioRendererMixers may be owned by garbage collected
+ // objects. During process shutdown they may be leaked, so, transitively,
+ // |mixers_| may leak (i.e., may be non-empty at this time) as well.
+}
+
+// static
+AudioRendererMixerManager& AudioRendererMixerManager::GetInstance() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(
+ AudioRendererMixerManager, instance,
+ (base::BindRepeating(&WebAudioDeviceFactory::NewAudioRendererMixerSink)));
+ return instance;
+}
+
+scoped_refptr<media::AudioRendererMixerInput>
+AudioRendererMixerManager::CreateInput(
+ const blink::LocalFrameToken& source_frame_token,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ media::AudioLatency::LatencyType latency) {
+ // AudioRendererMixerManager lives on the renderer thread and is destroyed on
+ // renderer thread destruction, so it's safe to pass its pointer to a mixer
+ // input.
+ //
+ // TODO(olka, grunell): |session_id| is always empty, delete since
+ // NewAudioRenderingMixingStrategy didn't ship, https://crbug.com/870836.
+ DCHECK(session_id.is_empty());
+ return base::MakeRefCounted<media::AudioRendererMixerInput>(
+ this, source_frame_token.value(), device_id, latency);
+}
+
+media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
+ const blink::LocalFrameToken& source_frame_token,
+ const media::AudioParameters& input_params,
+ media::AudioLatency::LatencyType latency,
+ const media::OutputDeviceInfo& sink_info,
+ scoped_refptr<media::AudioRendererSink> sink) {
+ // Ownership of the sink must be given to GetMixer().
+ DCHECK(sink->HasOneRef());
+ DCHECK_EQ(sink_info.device_status(), media::OUTPUT_DEVICE_STATUS_OK);
+
+ const MixerKey key(source_frame_token, input_params, latency,
+ sink_info.device_id());
+ base::AutoLock auto_lock(mixers_lock_);
+
+ auto it = mixers_.find(key);
+ if (it != mixers_.end()) {
+ auto new_count = ++it->second.ref_count;
+ CHECK(new_count != std::numeric_limits<decltype(new_count)>::max());
+
+ DVLOG(1) << "Reusing mixer: " << it->second.mixer;
+
+ // Sink will now be released unused, but still must be stopped.
+ //
+ // TODO(dalecurtis): Is it worth caching this sink instead for a future
+ // GetSink() call? We should experiment with a few top sites. We can't just
+ // drop in AudioRendererSinkCache here since it doesn't reuse sinks once
+ // they've been vended externally to the class.
+ sink->Stop();
+
+ return it->second.mixer;
+ }
+
+ const media::AudioParameters& mixer_output_params =
+ GetMixerOutputParams(input_params, sink_info.output_params(), latency);
+ media::AudioRendererMixer* mixer =
+ new media::AudioRendererMixer(mixer_output_params, std::move(sink));
+ mixers_[key] = {mixer, 1};
+ DVLOG(1) << __func__ << " mixer: " << mixer << " latency: " << latency
+ << "\n input: " << input_params.AsHumanReadableString()
+ << "\noutput: " << mixer_output_params.AsHumanReadableString();
+ return mixer;
+}
+
+scoped_refptr<media::AudioRendererSink> AudioRendererMixerManager::GetSink(
+ const blink::LocalFrameToken& source_frame_token,
+ const std::string& device_id) {
+ return create_sink_cb_.Run(
+ source_frame_token,
+ media::AudioSinkParameters(base::UnguessableToken(), device_id));
+}
+
+media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
+ const base::UnguessableToken& source_frame_token,
+ const media::AudioParameters& input_params,
+ media::AudioLatency::LatencyType latency,
+ const media::OutputDeviceInfo& sink_info,
+ scoped_refptr<media::AudioRendererSink> sink) {
+ // Ownership of the sink must be given to GetMixer().
+ DCHECK(sink->HasOneRef());
+ // Forward to the strongly typed version. We move the |sink| as GetMixer
+ // expects to be the sole owner at this point.
+ DCHECK(source_frame_token);
+ return GetMixer(blink::LocalFrameToken(source_frame_token), input_params,
+ latency, sink_info, std::move(sink));
+}
+
+void AudioRendererMixerManager::ReturnMixer(media::AudioRendererMixer* mixer) {
+ base::AutoLock auto_lock(mixers_lock_);
+ auto it = std::find_if(
+ mixers_.begin(), mixers_.end(),
+ [mixer](const std::pair<MixerKey, AudioRendererMixerReference>& val) {
+ return val.second.mixer == mixer;
+ });
+ DCHECK(it != mixers_.end());
+
+ // Only remove the mixer if AudioRendererMixerManager is the last owner.
+ it->second.ref_count--;
+ if (it->second.ref_count == 0) {
+ delete it->second.mixer;
+ mixers_.erase(it);
+ }
+}
+
+scoped_refptr<media::AudioRendererSink> AudioRendererMixerManager::GetSink(
+ const base::UnguessableToken& source_frame_token,
+ const std::string& device_id) {
+ // Forward to the strongly typed version.
+ DCHECK(source_frame_token);
+ return GetSink(blink::LocalFrameToken(source_frame_token), device_id);
+}
+
+AudioRendererMixerManager::MixerKey::MixerKey(
+ const blink::LocalFrameToken& source_frame_token,
+ const media::AudioParameters& params,
+ media::AudioLatency::LatencyType latency,
+ const std::string& device_id)
+ : source_frame_token(source_frame_token),
+ params(params),
+ latency(latency),
+ device_id(device_id) {}
+
+AudioRendererMixerManager::MixerKey::MixerKey(const MixerKey& other) = default;
+
+AudioRendererMixerManager::MixerKey::~MixerKey() = default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h
new file mode 100644
index 00000000000..fe3a7388fba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h
@@ -0,0 +1,181 @@
+// 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_RENDERER_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_MIXER_MANAGER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_MIXER_MANAGER_H_
+
+#include <bitset>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/unguessable_token.h"
+#include "media/audio/audio_device_description.h"
+#include "media/audio/audio_sink_parameters.h"
+#include "media/base/audio_latency.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/audio_renderer_mixer_pool.h"
+#include "media/base/output_device_info.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/platform/web_common.h"
+
+namespace media {
+class AudioRendererMixer;
+class AudioRendererMixerInput;
+class AudioRendererSink;
+} // namespace media
+
+namespace blink {
+
+// Manages sharing of an AudioRendererMixer among AudioRendererMixerInputs based
+// on their AudioParameters configuration. Inputs with the same AudioParameters
+// configuration will share a mixer while a new AudioRendererMixer will be
+// lazily created if one with the exact AudioParameters does not exist. When an
+// AudioRendererMixer is returned by AudioRendererMixerInput, it will be deleted
+// if its only other reference is held by AudioRendererMixerManager.
+//
+// There should only be one instance of AudioRendererMixerManager per render
+// thread.
+class BLINK_MODULES_EXPORT AudioRendererMixerManager
+ : public media::AudioRendererMixerPool {
+ public:
+ ~AudioRendererMixerManager() final;
+
+ // AudioRendererMixerManager instance which manages renderer side mixer
+ // instances shared based on configured audio parameters. Lazily created on
+ // first call.
+ static AudioRendererMixerManager& GetInstance();
+
+ // Creates an AudioRendererMixerInput with the proper callbacks necessary to
+ // retrieve an AudioRendererMixer instance from AudioRendererMixerManager.
+ // |source_frame_token| refers to the RenderFrame containing the entity
+ // rendering the audio. Caller must ensure AudioRendererMixerManager outlives
+ // the returned input. |device_id| and |session_id| identify the output
+ // device to use. If |device_id| is empty and |session_id| is nonzero,
+ // output device associated with the opened input device designated by
+ // |session_id| is used. Otherwise, |session_id| is ignored.
+ scoped_refptr<media::AudioRendererMixerInput> CreateInput(
+ const blink::LocalFrameToken& source_frame_token,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ media::AudioLatency::LatencyType latency);
+
+ // media::AudioRendererMixerPool implementation. The rest of the
+ // implementation is kept private (see comment below).
+ void ReturnMixer(media::AudioRendererMixer* mixer) final;
+
+ // media::AudioRendererMixerPool look-alikes, with strongly typed tokens.
+ // Clients in blink/ should use these functions.
+ media::AudioRendererMixer* GetMixer(
+ const blink::LocalFrameToken& source_frame_token,
+ const media::AudioParameters& input_params,
+ media::AudioLatency::LatencyType latency,
+ const media::OutputDeviceInfo& sink_info,
+ scoped_refptr<media::AudioRendererSink> sink);
+ scoped_refptr<media::AudioRendererSink> GetSink(
+ const blink::LocalFrameToken& source_frame_token,
+ const std::string& device_id);
+
+ protected:
+ // Callback which will be used to create sinks. See AudioDeviceFactory for
+ // more details on the parameters.
+ using CreateSinkCB =
+ base::RepeatingCallback<scoped_refptr<media::AudioRendererSink>(
+ const blink::LocalFrameToken& source_frame_token,
+ const media::AudioSinkParameters& params)>;
+
+ explicit AudioRendererMixerManager(CreateSinkCB create_sink_cb);
+
+ private:
+ friend class AudioRendererMixerManagerTest;
+
+ // media::AudioRendererMixerPool implementation. This interface faces
+ // code in media/ which uses untyped tokens, and is kept private so that
+ // blink/ clients prefer to use the strongly-typed-token variants.
+ media::AudioRendererMixer* GetMixer(
+ const base::UnguessableToken& source_frame_token,
+ const media::AudioParameters& input_params,
+ media::AudioLatency::LatencyType latency,
+ const media::OutputDeviceInfo& sink_info,
+ scoped_refptr<media::AudioRendererSink> sink) final;
+ scoped_refptr<media::AudioRendererSink> GetSink(
+ const base::UnguessableToken& source_frame_token,
+ const std::string& device_id) final;
+
+ // Define a key so that only those AudioRendererMixerInputs from the same
+ // RenderView, AudioParameters and output device can be mixed together.
+ struct MixerKey {
+ MixerKey(const blink::LocalFrameToken& source_frame_token,
+ const media::AudioParameters& params,
+ media::AudioLatency::LatencyType latency,
+ const std::string& device_id);
+ MixerKey(const MixerKey& other);
+ ~MixerKey();
+ blink::LocalFrameToken source_frame_token;
+ media::AudioParameters params;
+ media::AudioLatency::LatencyType latency;
+ std::string device_id;
+ };
+
+ // Custom compare operator for the AudioRendererMixerMap. Allows reuse of
+ // mixers where only irrelevant keys mismatch.
+ struct MixerKeyCompare {
+ bool operator()(const MixerKey& a, const MixerKey& b) const {
+ if (a.source_frame_token != b.source_frame_token)
+ return a.source_frame_token < b.source_frame_token;
+ if (a.params.channels() != b.params.channels())
+ return a.params.channels() < b.params.channels();
+
+ if (a.latency != b.latency)
+ return a.latency < b.latency;
+
+ // TODO(olka) add buffer duration comparison for LATENCY_EXACT_MS when
+ // adding support for it.
+ DCHECK_NE(media::AudioLatency::LATENCY_EXACT_MS, a.latency);
+
+ // Ignore format(), and frames_per_buffer(), these parameters do not
+ // affect mixer reuse. All AudioRendererMixer units disable FIFO, so
+ // frames_per_buffer() can be safely ignored.
+ if (a.params.channel_layout() != b.params.channel_layout())
+ return a.params.channel_layout() < b.params.channel_layout();
+ if (a.params.effects() != b.params.effects())
+ return a.params.effects() < b.params.effects();
+
+ if (media::AudioDeviceDescription::IsDefaultDevice(a.device_id) &&
+ media::AudioDeviceDescription::IsDefaultDevice(b.device_id)) {
+ // Both device IDs represent the same default device => do not compare
+ // them.
+ return false;
+ }
+
+ return a.device_id < b.device_id;
+ }
+ };
+
+ const CreateSinkCB create_sink_cb_;
+
+ // Map of MixerKey to <AudioRendererMixer, Count>. Count allows
+ // AudioRendererMixerManager to keep track explicitly (v.s. RefCounted which
+ // is implicit) of the number of outstanding AudioRendererMixers.
+ struct AudioRendererMixerReference {
+ media::AudioRendererMixer* mixer;
+ size_t ref_count;
+ };
+
+ using AudioRendererMixerMap =
+ base::flat_map<MixerKey, AudioRendererMixerReference, MixerKeyCompare>;
+
+ // Active mixers.
+ AudioRendererMixerMap mixers_;
+ base::Lock mixers_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManager);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_MIXER_MANAGER_H_
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager_test.cc b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager_test.cc
new file mode 100644
index 00000000000..8cbbd2b0265
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager_test.cc
@@ -0,0 +1,786 @@
+// 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/renderer/modules/media/audio/audio_renderer_mixer_manager.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/notreached.h"
+#include "base/run_loop.h"
+#include "build/build_config.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/audio_renderer_mixer.h"
+#include "media/base/audio_renderer_mixer_input.h"
+#include "media/base/fake_audio_render_callback.h"
+#include "media/base/mock_audio_renderer_sink.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+const int kSampleRate = 48000;
+const int kBufferSize = 8192;
+const int kHardwareSampleRate = 44100;
+const int kHardwareBufferSize = 128;
+const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
+const media::ChannelLayout kAnotherChannelLayout = media::CHANNEL_LAYOUT_2_1;
+const char* const kDefaultDeviceId =
+ media::AudioDeviceDescription::kDefaultDeviceId;
+const char kAnotherDeviceId[] = "another-device-id";
+const char kMatchedDeviceId[] = "matched-device-id";
+const char kNonexistentDeviceId[] = "nonexistent-device-id";
+
+const LocalFrameToken kFrameToken;
+const LocalFrameToken kAnotherFrameToken;
+} // namespace
+
+using media::AudioLatency;
+using media::AudioParameters;
+
+class AudioRendererMixerManagerTest : public testing::Test {
+ public:
+ AudioRendererMixerManagerTest()
+ : manager_(new AudioRendererMixerManager(
+ base::BindRepeating(&AudioRendererMixerManagerTest::GetPlainSink,
+ base::Unretained(this)))) {}
+
+ scoped_refptr<media::MockAudioRendererSink> CreateNormalSink(
+ const std::string& device_id = std::string(kDefaultDeviceId)) {
+ auto sink = base::MakeRefCounted<media::MockAudioRendererSink>(
+ device_id, media::OUTPUT_DEVICE_STATUS_OK,
+ AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
+ kHardwareSampleRate, kHardwareBufferSize));
+ EXPECT_CALL(*sink, Stop()).Times(1);
+ return sink;
+ }
+
+ scoped_refptr<media::MockAudioRendererSink> CreateNoDeviceSink() {
+ return base::MakeRefCounted<media::MockAudioRendererSink>(
+ kNonexistentDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND);
+ }
+
+ scoped_refptr<media::MockAudioRendererSink> CreateMatchedDeviceSink() {
+ auto sink = base::MakeRefCounted<media::MockAudioRendererSink>(
+ kMatchedDeviceId, media::OUTPUT_DEVICE_STATUS_OK);
+ EXPECT_CALL(*sink, Stop()).Times(1);
+ return sink;
+ }
+
+ enum class SinkUseState { kExistingSink, kNewSink };
+ media::AudioRendererMixer* GetMixer(const LocalFrameToken& source_frame_token,
+ const media::AudioParameters& params,
+ AudioLatency::LatencyType latency,
+ const std::string& device_id,
+ SinkUseState sink_state) {
+ auto sink = GetSink(
+ source_frame_token,
+ media::AudioSinkParameters(base::UnguessableToken(), device_id));
+ auto device_info = sink->GetOutputDeviceInfo();
+ if (sink_state == SinkUseState::kNewSink)
+ EXPECT_CALL(*sink, Start()).Times(1);
+ return manager_->GetMixer(source_frame_token, params, latency, device_info,
+ std::move(sink));
+ }
+
+ void ReturnMixer(media::AudioRendererMixer* mixer) {
+ return manager_->ReturnMixer(mixer);
+ }
+
+ scoped_refptr<media::AudioRendererMixerInput> CreateInputHelper(
+ const LocalFrameToken& source_frame_token,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ media::AudioLatency::LatencyType latency,
+ const media::AudioParameters params,
+ media::AudioRendererSink::RenderCallback* callback) {
+ auto input = manager_->CreateInput(source_frame_token, session_id,
+ device_id, latency);
+ input->GetOutputDeviceInfoAsync(
+ base::DoNothing()); // Primes input, needed for tests.
+ base::RunLoop().RunUntilIdle();
+ input->Initialize(params, callback);
+ return input;
+ }
+
+ // Number of instantiated mixers.
+ int mixer_count() { return manager_->mixers_.size(); }
+
+ protected:
+ scoped_refptr<media::MockAudioRendererSink> GetSink(
+ const LocalFrameToken& source_frame_token,
+ const media::AudioSinkParameters& params) {
+ if ((params.device_id == kDefaultDeviceId) ||
+ (params.device_id == kAnotherDeviceId)) {
+ return mock_sink_ ? std::move(mock_sink_)
+ : CreateNormalSink(params.device_id);
+ }
+ if (params.device_id == kNonexistentDeviceId)
+ return CreateNoDeviceSink();
+ if (params.device_id.empty()) {
+ // The sink used to get device ID from session ID if it's not empty
+ return params.session_id
+ ? CreateMatchedDeviceSink()
+ : (mock_sink_ ? std::move(mock_sink_)
+ : CreateNormalSink(params.device_id));
+ }
+ if (params.device_id == kMatchedDeviceId)
+ return CreateMatchedDeviceSink();
+
+ NOTREACHED();
+ return nullptr;
+ }
+
+ std::unique_ptr<AudioRendererMixerManager> manager_;
+ scoped_refptr<media::MockAudioRendererSink> mock_sink_;
+
+ private:
+ scoped_refptr<media::AudioRendererSink> GetPlainSink(
+ const LocalFrameToken& source_frame_token,
+ const media::AudioSinkParameters& params) {
+ return GetSink(source_frame_token, params);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest);
+};
+
+// Verify GetMixer() and ReturnMixer() both work as expected; particularly with
+// respect to the explicit ref counting done.
+TEST_F(AudioRendererMixerManagerTest, GetReturnMixer) {
+ // There should be no mixers outstanding to start with.
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params1(media::AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params1, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ // The same parameters should return the same mixer1.
+ EXPECT_EQ(mixer1,
+ GetMixer(kFrameToken, params1, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink));
+ EXPECT_EQ(1, mixer_count());
+
+ // Return the extra mixer we just acquired.
+ ReturnMixer(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioParameters params2(AudioParameters::AUDIO_PCM_LINEAR,
+ kAnotherChannelLayout, kSampleRate * 2,
+ kBufferSize * 2);
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params2, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer2);
+ EXPECT_EQ(2, mixer_count());
+
+ // Different parameters should result in a different mixer1.
+ EXPECT_NE(mixer1, mixer2);
+
+ // Return both outstanding mixers.
+ ReturnMixer(mixer1);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify GetMixer() correctly deduplicates mixer with irrelevant AudioParameter
+// differences.
+TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
+ EXPECT_EQ(mixer_count(), 0);
+
+ media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params1, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ // Different sample rates, formats, bit depths, and buffer sizes should not
+ // result in a different mixer.
+ media::AudioParameters params2(AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kChannelLayout, kSampleRate * 2,
+ kBufferSize * 2);
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params2, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ EXPECT_EQ(mixer1, mixer2);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(1, mixer_count());
+
+ // Modify some parameters that do matter: channel layout
+ media::AudioParameters params3(AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ kAnotherChannelLayout, kSampleRate,
+ kBufferSize);
+ ASSERT_NE(params3.channel_layout(), params1.channel_layout());
+ media::AudioRendererMixer* mixer3 =
+ GetMixer(kFrameToken, params3, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ EXPECT_NE(mixer1, mixer3);
+ EXPECT_EQ(2, mixer_count());
+ ReturnMixer(mixer3);
+ EXPECT_EQ(1, mixer_count());
+
+ // Return final mixer.
+ ReturnMixer(mixer1);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify CreateInput() provides AudioRendererMixerInput with the appropriate
+// callbacks and they are working as expected. Also, verify that separate
+// mixers are created for separate RenderFrames, even though the
+// AudioParameters are the same.
+TEST_F(AudioRendererMixerManagerTest, CreateInput) {
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+
+ // Create two mixer inputs and ensure this doesn't instantiate any mixers yet.
+ EXPECT_EQ(0, mixer_count());
+ media::FakeAudioRenderCallback callback(0, kSampleRate);
+ mock_sink_ = CreateNormalSink();
+ EXPECT_CALL(*mock_sink_, Start()).Times(1);
+ auto input =
+ CreateInputHelper(kFrameToken, base::UnguessableToken(), kDefaultDeviceId,
+ AudioLatency::LATENCY_PLAYBACK, params, &callback);
+ EXPECT_EQ(0, mixer_count());
+ media::FakeAudioRenderCallback another_callback(1, kSampleRate);
+
+ EXPECT_FALSE(!!mock_sink_);
+ mock_sink_ = CreateNormalSink();
+ EXPECT_CALL(*mock_sink_, Start()).Times(1);
+ auto another_input = CreateInputHelper(
+ kAnotherFrameToken, base::UnguessableToken(), kDefaultDeviceId,
+ AudioLatency::LATENCY_PLAYBACK, params, &another_callback);
+ EXPECT_EQ(0, mixer_count());
+
+ // Implicitly test that AudioRendererMixerInput was provided with the expected
+ // callbacks needed to acquire an AudioRendererMixer and return it.
+ input->Start();
+ EXPECT_EQ(1, mixer_count());
+ another_input->Start();
+ EXPECT_EQ(2, mixer_count());
+
+ // Destroying the inputs should destroy the mixers.
+ input->Stop();
+ input = nullptr;
+ EXPECT_EQ(1, mixer_count());
+ another_input->Stop();
+ another_input = nullptr;
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify CreateInput() provided with session id creates AudioRendererMixerInput
+// with the appropriate callbacks and they are working as expected.
+//
+// TODO(grunell): |session_id| support currently requires calling the
+// synchronous GetOutputDeviceInfo call, this is not allowed. So this test is
+// disabled. This should be deleted in the future, https://crbug.com/870836.
+TEST_F(AudioRendererMixerManagerTest, DISABLED_CreateInputWithSessionId) {
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ media::FakeAudioRenderCallback callback(0, kSampleRate);
+ EXPECT_EQ(0, mixer_count());
+
+ // Empty device id, zero session id;
+ auto input_to_default_device = CreateInputHelper(
+ kFrameToken, base::UnguessableToken(), // session_id
+ std::string(), AudioLatency::LATENCY_PLAYBACK, params, &callback);
+ EXPECT_EQ(0, mixer_count());
+
+ // Specific device id, zero session id;
+ auto input_to_another_device = CreateInputHelper(
+ kFrameToken, base::UnguessableToken(), // session_id
+ kMatchedDeviceId, AudioLatency::LATENCY_PLAYBACK, params, &callback);
+ EXPECT_EQ(0, mixer_count());
+
+ // Specific device id, non-zero session id (to be ignored);
+ auto input_to_matched_device = CreateInputHelper(
+ kFrameToken,
+ base::UnguessableToken::Create(), // session id
+ kAnotherDeviceId, AudioLatency::LATENCY_PLAYBACK, params, &callback);
+ EXPECT_EQ(0, mixer_count());
+
+ // Empty device id, non-zero session id;
+ auto input_to_matched_device_with_session_id = CreateInputHelper(
+ kFrameToken,
+ base::UnguessableToken::Create(), // session id
+ std::string(), AudioLatency::LATENCY_PLAYBACK, params, &callback);
+ EXPECT_EQ(0, mixer_count());
+
+ // Implicitly test that AudioRendererMixerInput was provided with the expected
+ // callbacks needed to acquire an AudioRendererMixer and return it.
+ input_to_default_device->Start();
+ EXPECT_EQ(1, mixer_count());
+
+ input_to_another_device->Start();
+ EXPECT_EQ(2, mixer_count());
+
+ input_to_matched_device->Start();
+ EXPECT_EQ(3, mixer_count());
+
+ // Should go to the same device as the input above.
+ input_to_matched_device_with_session_id->Start();
+ EXPECT_EQ(3, mixer_count());
+
+ // Destroying the inputs should destroy the mixers.
+ input_to_default_device->Stop();
+ input_to_default_device = nullptr;
+ EXPECT_EQ(2, mixer_count());
+ input_to_another_device->Stop();
+ input_to_another_device = nullptr;
+ EXPECT_EQ(1, mixer_count());
+ input_to_matched_device->Stop();
+ input_to_matched_device = nullptr;
+ EXPECT_EQ(1, mixer_count());
+ input_to_matched_device_with_session_id->Stop();
+ input_to_matched_device_with_session_id = nullptr;
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify GetMixer() correctly creates different mixers with the same
+// parameters, but different device ID.
+TEST_F(AudioRendererMixerManagerTest, MixerDevices) {
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kAnotherDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer2);
+ EXPECT_EQ(2, mixer_count());
+ EXPECT_NE(mixer1, mixer2);
+
+ ReturnMixer(mixer1);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify GetMixer() correctly deduplicate mixers with the same
+// parameters and default device ID, even if one is "" and one is "default".
+TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentDefaultDeviceIDs) {
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ std::string(), SinkUseState::kExistingSink);
+ ASSERT_TRUE(mixer2);
+ EXPECT_EQ(1, mixer_count());
+ EXPECT_EQ(mixer1, mixer2);
+
+ ReturnMixer(mixer1);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify that GetMixer() correctly returns a null mixer and an appropriate
+// status code when a nonexistent device is requested.
+TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) {
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+
+ auto sink =
+ GetSink(kFrameToken, media::AudioSinkParameters(base::UnguessableToken(),
+ kNonexistentDeviceId));
+ auto device_info = sink->GetOutputDeviceInfo();
+
+ EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ device_info.device_status());
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify GetMixer() correctly deduplicate mixers basing on latency
+// requirements.
+TEST_F(AudioRendererMixerManagerTest, LatencyMixing) {
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ ASSERT_TRUE(mixer2);
+ EXPECT_EQ(mixer1, mixer2); // Same latency => same mixer.
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioRendererMixer* mixer3 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_RTC, kDefaultDeviceId,
+ SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer3);
+ EXPECT_NE(mixer1, mixer3);
+ EXPECT_EQ(2, mixer_count()); // Another latency => another mixer.
+
+ media::AudioRendererMixer* mixer4 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_RTC, kDefaultDeviceId,
+ SinkUseState::kExistingSink);
+ EXPECT_EQ(mixer3, mixer4);
+ EXPECT_EQ(2, mixer_count()); // Same latency => same mixer.
+
+ media::AudioRendererMixer* mixer5 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_INTERACTIVE,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer5);
+ EXPECT_EQ(3, mixer_count()); // Another latency => another mixer.
+
+ media::AudioRendererMixer* mixer6 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_INTERACTIVE,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ EXPECT_EQ(mixer5, mixer6);
+ EXPECT_EQ(3, mixer_count()); // Same latency => same mixer.
+
+ ReturnMixer(mixer1);
+ EXPECT_EQ(3, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(2, mixer_count());
+ ReturnMixer(mixer3);
+ EXPECT_EQ(2, mixer_count());
+ ReturnMixer(mixer4);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer5);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer6);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify GetMixer() correctly deduplicate mixers basing on the effects
+// requirements.
+TEST_F(AudioRendererMixerManagerTest, EffectsMixing) {
+ EXPECT_EQ(0, mixer_count());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, kSampleRate, kBufferSize);
+ params.set_effects(1);
+ media::AudioRendererMixer* mixer1 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer1);
+ EXPECT_EQ(1, mixer_count());
+
+ media::AudioRendererMixer* mixer2 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ ASSERT_TRUE(mixer2);
+ EXPECT_EQ(mixer1, mixer2); // Same effects => same mixer.
+ EXPECT_EQ(1, mixer_count());
+
+ params.set_effects(2);
+ media::AudioRendererMixer* mixer3 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer3);
+ EXPECT_NE(mixer1, mixer3);
+ EXPECT_EQ(2, mixer_count()); // Another effects => another mixer.
+
+ media::AudioRendererMixer* mixer4 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ EXPECT_EQ(mixer3, mixer4);
+ EXPECT_EQ(2, mixer_count()); // Same effects => same mixer.
+
+ params.set_effects(3);
+ media::AudioRendererMixer* mixer5 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+ ASSERT_TRUE(mixer5);
+ EXPECT_EQ(3, mixer_count()); // Another effects => another mixer.
+
+ media::AudioRendererMixer* mixer6 =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kExistingSink);
+ EXPECT_EQ(mixer5, mixer6);
+ EXPECT_EQ(3, mixer_count()); // Same effects => same mixer.
+
+ ReturnMixer(mixer1);
+ EXPECT_EQ(3, mixer_count());
+ ReturnMixer(mixer2);
+ EXPECT_EQ(2, mixer_count());
+ ReturnMixer(mixer3);
+ EXPECT_EQ(2, mixer_count());
+ ReturnMixer(mixer4);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer5);
+ EXPECT_EQ(1, mixer_count());
+ ReturnMixer(mixer6);
+ EXPECT_EQ(0, mixer_count());
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for Playback
+// latency.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback) {
+ mock_sink_ = CreateNormalSink();
+
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(44100,
+ mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(
+ 128,
+ mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+ params.set_latency_tag(AudioLatency::LATENCY_PLAYBACK);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, params.latency_tag(), kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ if (AudioLatency::IsResamplingPassthroughSupported(params.latency_tag())) {
+ // Expecting input sample rate
+ EXPECT_EQ(32000, mixer->get_output_params_for_testing().sample_rate());
+ // Round up 20 ms (640) to the power of 2.
+ EXPECT_EQ(1024, mixer->get_output_params_for_testing().frames_per_buffer());
+ } else {
+ // Expecting hardware sample rate
+ EXPECT_EQ(44100, mixer->get_output_params_for_testing().sample_rate());
+
+// 20 ms at 44100 is 882 frames per buffer.
+#if defined(OS_WIN)
+ // Round up 882 to the nearest multiple of the output buffer size (128).
+ // which is 7 * 128 = 896
+ EXPECT_EQ(896, mixer->get_output_params_for_testing().frames_per_buffer());
+#else
+ // Round up 882 to the power of 2.
+ EXPECT_EQ(1024, mixer->get_output_params_for_testing().frames_per_buffer());
+#endif // defined(OS_WIN)
+ }
+
+ ReturnMixer(mixer);
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for Playback
+// latency when the device buffer size exceeds 20 ms.
+TEST_F(AudioRendererMixerManagerTest,
+ MixerParamsLatencyPlaybackLargeDeviceBufferSize) {
+ mock_sink_ = new media::MockAudioRendererSink(
+ std::string(), media::OUTPUT_DEVICE_STATUS_OK,
+ AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44100,
+ 2048));
+ EXPECT_CALL(*mock_sink_, Stop()).Times(1);
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+ params.set_latency_tag(AudioLatency::LATENCY_PLAYBACK);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, params.latency_tag(), kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ // 20 ms at 44100 is 882 frames per buffer.
+ if (AudioLatency::IsResamplingPassthroughSupported(params.latency_tag())) {
+ // Expecting input sample rate
+ EXPECT_EQ(32000, mixer->get_output_params_for_testing().sample_rate());
+ } else {
+ // Expecting hardware sample rate
+ EXPECT_EQ(44100, mixer->get_output_params_for_testing().sample_rate());
+ }
+
+ // Prefer device buffer size (2048) if is larger than 20 ms buffer size.
+ EXPECT_EQ(2048, mixer->get_output_params_for_testing().frames_per_buffer());
+
+ ReturnMixer(mixer);
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for Playback
+// latency when output audio is fake.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio) {
+ mock_sink_ = new media::MockAudioRendererSink(
+ std::string(), media::OUTPUT_DEVICE_STATUS_OK,
+ AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100,
+ 2048));
+ EXPECT_CALL(*mock_sink_, Stop()).Times(1);
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_PLAYBACK,
+ kDefaultDeviceId, SinkUseState::kNewSink);
+
+ // Expecting input sample rate
+ EXPECT_EQ(32000, mixer->get_output_params_for_testing().sample_rate());
+
+// 20 ms at 32000 is 640 frames per buffer.
+#if defined(OS_WIN)
+ // Use 20 ms buffer.
+ EXPECT_EQ(640, mixer->get_output_params_for_testing().frames_per_buffer());
+#else
+ // Ignore device buffer size, round up 640 to the power of 2.
+ EXPECT_EQ(1024, mixer->get_output_params_for_testing().frames_per_buffer());
+#endif // defined(OS_WIN)
+
+ ReturnMixer(mixer);
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for RTC latency.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc) {
+ mock_sink_ = CreateNormalSink();
+
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(44100,
+ mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(
+ 128,
+ mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+ params.set_latency_tag(AudioLatency::LATENCY_RTC);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, params.latency_tag(), kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ int output_sample_rate =
+ AudioLatency::IsResamplingPassthroughSupported(params.latency_tag())
+ ? 32000
+ : 44100;
+
+ EXPECT_EQ(output_sample_rate,
+ mixer->get_output_params_for_testing().sample_rate());
+
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
+ defined(OS_FUCHSIA)
+ // Use 10 ms buffer (441 frames per buffer).
+ EXPECT_EQ(output_sample_rate / 100,
+ mixer->get_output_params_for_testing().frames_per_buffer());
+#elif defined(OS_ANDROID)
+ // If hardware buffer size (128) is less than 20 ms (882), use 20 ms buffer
+ // (otherwise, use hardware buffer).
+ EXPECT_EQ(882, mixer->get_output_params_for_testing().frames_per_buffer());
+#else
+ // Use hardware buffer size (128).
+ EXPECT_EQ(128, mixer->get_output_params_for_testing().frames_per_buffer());
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
+
+ ReturnMixer(mixer);
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for RTC latency
+// when output audio is fake.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio) {
+ mock_sink_ = new media::MockAudioRendererSink(
+ std::string(), media::OUTPUT_DEVICE_STATUS_OK,
+ AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100, 128));
+ EXPECT_CALL(*mock_sink_, Stop()).Times(1);
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, AudioLatency::LATENCY_RTC, kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ // Expecting input sample rate.
+ EXPECT_EQ(32000, mixer->get_output_params_for_testing().sample_rate());
+
+ // 10 ms at 32000 is 320 frames per buffer. Expect it on all the platforms for
+ // fake audio output.
+ EXPECT_EQ(320, mixer->get_output_params_for_testing().frames_per_buffer());
+
+ ReturnMixer(mixer);
+}
+
+// Verify output bufer size of the mixer is correctly adjusted for Interactive
+// latency.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive) {
+ mock_sink_ = CreateNormalSink();
+
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(44100,
+ mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
+ // Expecting hardware buffer size of 128 frames
+ EXPECT_EQ(
+ 128,
+ mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
+
+ media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ kChannelLayout, 32000, 512);
+ params.set_latency_tag(AudioLatency::LATENCY_INTERACTIVE);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, params.latency_tag(), kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ if (AudioLatency::IsResamplingPassthroughSupported(params.latency_tag())) {
+ // Expecting input sample rate.
+ EXPECT_EQ(32000, mixer->get_output_params_for_testing().sample_rate());
+ } else {
+ // Expecting hardware sample rate.
+ EXPECT_EQ(44100, mixer->get_output_params_for_testing().sample_rate());
+ }
+
+ // Expect hardware buffer size.
+ EXPECT_EQ(128, mixer->get_output_params_for_testing().frames_per_buffer());
+
+ ReturnMixer(mixer);
+}
+
+// Verify output parameters are the same as input properties for bitstream
+// formats.
+TEST_F(AudioRendererMixerManagerTest, MixerParamsBitstreamFormat) {
+ mock_sink_ = new media::MockAudioRendererSink(
+ std::string(), media::OUTPUT_DEVICE_STATUS_OK,
+ AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44100,
+ 2048));
+ EXPECT_CALL(*mock_sink_, Stop()).Times(1);
+
+ media::AudioParameters params(AudioParameters::AUDIO_BITSTREAM_EAC3,
+ kAnotherChannelLayout, 32000, 512);
+ params.set_latency_tag(AudioLatency::LATENCY_PLAYBACK);
+
+ media::AudioRendererMixer* mixer =
+ GetMixer(kFrameToken, params, params.latency_tag(), kDefaultDeviceId,
+ SinkUseState::kNewSink);
+
+ // Output parameters should be the same as input properties for bitstream
+ // formats.
+ EXPECT_EQ(params.format(), mixer->get_output_params_for_testing().format());
+ EXPECT_EQ(params.channel_layout(),
+ mixer->get_output_params_for_testing().channel_layout());
+ EXPECT_EQ(params.sample_rate(),
+ mixer->get_output_params_for_testing().sample_rate());
+ EXPECT_EQ(params.frames_per_buffer(),
+ mixer->get_output_params_for_testing().frames_per_buffer());
+
+ ReturnMixer(mixer);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.cc b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.cc
new file mode 100644
index 00000000000..18472ad8283
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.cc
@@ -0,0 +1,365 @@
+// 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/media/audio/audio_renderer_sink_cache.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/synchronization/lock.h"
+#include "base/task/post_task.h"
+#include "base/trace_event/trace_event.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_renderer_sink.h"
+#include "third_party/blink/public/web/modules/media/audio/web_audio_device_factory.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.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/platform/supplementable.h"
+
+namespace blink {
+
+AudioRendererSinkCache* AudioRendererSinkCache::instance_ = nullptr;
+
+class AudioRendererSinkCache::FrameObserver final
+ : public GarbageCollected<AudioRendererSinkCache::FrameObserver>,
+ public Supplement<LocalFrame>,
+ public ExecutionContextLifecycleObserver {
+ public:
+ static const char kSupplementName[];
+ static FrameObserver* From(LocalFrame& frame) {
+ return Supplement<LocalFrame>::From<FrameObserver>(frame);
+ }
+
+ explicit FrameObserver(LocalFrame& frame)
+ : Supplement<LocalFrame>(frame),
+ ExecutionContextLifecycleObserver(frame.DomWindow()) {}
+ ~FrameObserver() { DCHECK(dropped_frame_cached_); }
+
+ void Trace(Visitor* visitor) const final {
+ Supplement<LocalFrame>::Trace(visitor);
+ ExecutionContextLifecycleObserver::Trace(visitor);
+ }
+
+ // ExecutionContextLifecycleObserver implementation.
+ void ContextDestroyed() override { DropFrameCache(); }
+
+ private:
+ void DropFrameCache() {
+ dropped_frame_cached_ = true;
+
+ if (!AudioRendererSinkCache::instance_)
+ return;
+ if (!GetSupplementable())
+ return;
+
+ LocalFrameToken frame_token = GetSupplementable()->GetLocalFrameToken();
+ AudioRendererSinkCache::instance_->DropSinksForFrame(frame_token);
+ }
+
+ bool dropped_frame_cached_ = false;
+ DISALLOW_COPY_AND_ASSIGN(FrameObserver);
+};
+
+const char AudioRendererSinkCache::FrameObserver::kSupplementName[] =
+ "AudioRendererSinkCache::FrameObserver";
+
+namespace {
+
+enum GetOutputDeviceInfoCacheUtilization {
+ // No cached sink found.
+ SINK_CACHE_MISS_NO_SINK = 0,
+
+ // If session id is used to specify a device, we always have to create and
+ // cache a new sink.
+ SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID = 1,
+
+ // Output parmeters for an already-cached sink are requested.
+ SINK_CACHE_HIT = 2,
+
+ // For UMA.
+ SINK_CACHE_LAST_ENTRY
+};
+
+bool SinkIsHealthy(media::AudioRendererSink* sink) {
+ return sink->GetOutputDeviceInfo().device_status() ==
+ media::OUTPUT_DEVICE_STATUS_OK;
+}
+
+} // namespace
+
+// Cached sink data.
+struct AudioRendererSinkCache::CacheEntry {
+ LocalFrameToken source_frame_token;
+ std::string device_id;
+ scoped_refptr<media::AudioRendererSink> sink; // Sink instance
+ bool used; // True if in use by a client.
+};
+
+// static
+void AudioRendererSinkCache::InstallFrameObserver(LocalFrame& frame) {
+ if (AudioRendererSinkCache::FrameObserver::From(frame))
+ return;
+ Supplement<LocalFrame>::ProvideTo(
+ frame,
+ MakeGarbageCollected<AudioRendererSinkCache::FrameObserver>(frame));
+}
+
+AudioRendererSinkCache::AudioRendererSinkCache(
+ scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner,
+ CreateSinkCallback create_sink_cb,
+ base::TimeDelta delete_timeout)
+ : cleanup_task_runner_(std::move(cleanup_task_runner)),
+ create_sink_cb_(std::move(create_sink_cb)),
+ delete_timeout_(delete_timeout) {
+ DCHECK(!instance_);
+ instance_ = this;
+}
+
+AudioRendererSinkCache::~AudioRendererSinkCache() {
+ // We just release all the cached sinks here. Stop them first.
+ // We can stop all the sinks, no matter they are used or not, since
+ // everything is being destroyed anyways.
+ for (auto& entry : cache_)
+ entry.sink->Stop();
+
+ if (instance_ == this)
+ instance_ = nullptr;
+}
+
+media::OutputDeviceInfo AudioRendererSinkCache::GetSinkInfo(
+ const LocalFrameToken& source_frame_token,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id) {
+ TRACE_EVENT_BEGIN2("audio", "AudioRendererSinkCache::GetSinkInfo",
+ "frame_token", source_frame_token.ToString(), "device id",
+ device_id);
+
+ if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
+ device_id)) {
+ // We are provided with session id instead of device id. Session id is
+ // unique, so we can't find any matching sink. Creating a new one.
+ scoped_refptr<media::AudioRendererSink> sink =
+ create_sink_cb_.Run(source_frame_token, {session_id, device_id});
+
+ CacheOrStopUnusedSink(source_frame_token,
+ sink->GetOutputDeviceInfo().device_id(), sink);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
+ SINK_CACHE_MISS_CANNOT_LOOKUP_BY_SESSION_ID, SINK_CACHE_LAST_ENTRY);
+ TRACE_EVENT_END1("audio", "AudioRendererSinkCache::GetSinkInfo", "result",
+ "Cache not used due to using |session_id|");
+
+ return sink->GetOutputDeviceInfo();
+ }
+ // Ignore session id.
+ {
+ base::AutoLock auto_lock(cache_lock_);
+ auto cache_iter = FindCacheEntry_Locked(source_frame_token, device_id,
+ false /* unused_only */);
+ if (cache_iter != cache_.end()) {
+ // A matching cached sink is found.
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
+ SINK_CACHE_HIT, SINK_CACHE_LAST_ENTRY);
+ TRACE_EVENT_END1("audio", "AudioRendererSinkCache::GetSinkInfo", "result",
+ "Cache hit");
+ return cache_iter->sink->GetOutputDeviceInfo();
+ }
+ }
+
+ // No matching sink found, create a new one.
+ scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run(
+ source_frame_token,
+ media::AudioSinkParameters(base::UnguessableToken(), device_id));
+
+ CacheOrStopUnusedSink(source_frame_token, device_id, sink);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization",
+ SINK_CACHE_MISS_NO_SINK, SINK_CACHE_LAST_ENTRY);
+
+ TRACE_EVENT_END1("audio", "AudioRendererSinkCache::GetSinkInfo", "result",
+ "Cache miss");
+ // |sink| is ref-counted, so it's ok if it is removed from cache before we
+ // get here.
+ return sink->GetOutputDeviceInfo();
+}
+
+scoped_refptr<media::AudioRendererSink> AudioRendererSinkCache::GetSink(
+ const LocalFrameToken& source_frame_token,
+ const std::string& device_id) {
+ UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.SinkCache.UsedForSinkCreation",
+ true);
+ TRACE_EVENT_BEGIN2("audio", "AudioRendererSinkCache::GetSink", "frame_token",
+ source_frame_token.ToString(), "device id", device_id);
+
+ base::AutoLock auto_lock(cache_lock_);
+
+ auto cache_iter = FindCacheEntry_Locked(source_frame_token, device_id,
+ true /* unused sink only */);
+
+ if (cache_iter != cache_.end()) {
+ // Found unused sink; mark it as used and return.
+ cache_iter->used = true;
+ UMA_HISTOGRAM_BOOLEAN(
+ "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", true);
+ TRACE_EVENT_END1("audio", "AudioRendererSinkCache::GetSink", "result",
+ "Cache hit");
+ return cache_iter->sink;
+ }
+
+ // No unused sink is found, create one, mark it used, cache it and return.
+ CacheEntry cache_entry = {
+ source_frame_token, device_id,
+ create_sink_cb_.Run(
+ source_frame_token,
+ media::AudioSinkParameters(base::UnguessableToken(), device_id)),
+ true /* used */};
+
+ if (SinkIsHealthy(cache_entry.sink.get())) {
+ TRACE_EVENT_INSTANT0("audio",
+ "AudioRendererSinkCache::GetSink: caching new sink",
+ TRACE_EVENT_SCOPE_THREAD);
+ cache_.push_back(cache_entry);
+ }
+
+ TRACE_EVENT_END1("audio", "AudioRendererSinkCache::GetSink", "result",
+ "Cache miss");
+ return cache_entry.sink;
+}
+
+void AudioRendererSinkCache::ReleaseSink(
+ const media::AudioRendererSink* sink_ptr) {
+ // We don't know the sink state, so won't reuse it. Delete it immediately.
+ DeleteSink(sink_ptr, true);
+}
+
+void AudioRendererSinkCache::DeleteLaterIfUnused(
+ const media::AudioRendererSink* sink_ptr) {
+ cleanup_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&AudioRendererSinkCache::DeleteSink,
+ // Unretained is safe here since this is a process-wide
+ // singleton and tests will ensure lifetime.
+ base::Unretained(this), base::RetainedRef(sink_ptr),
+ false /*do not delete if used*/),
+ delete_timeout_);
+}
+
+void AudioRendererSinkCache::DeleteSink(
+ const media::AudioRendererSink* sink_ptr,
+ bool force_delete_used) {
+ DCHECK(sink_ptr);
+
+ scoped_refptr<media::AudioRendererSink> sink_to_stop;
+
+ {
+ base::AutoLock auto_lock(cache_lock_);
+
+ // Looking up the sink by its pointer.
+ auto cache_iter = std::find_if(cache_.begin(), cache_.end(),
+ [sink_ptr](const CacheEntry& val) {
+ return val.sink.get() == sink_ptr;
+ });
+
+ if (cache_iter == cache_.end())
+ return;
+
+ // When |force_delete_used| is set, it's expected that we are deleting a
+ // used sink.
+ DCHECK((!force_delete_used) || (force_delete_used && cache_iter->used))
+ << "Attempt to delete a non-acquired sink.";
+
+ if (!force_delete_used && cache_iter->used)
+ return;
+
+ // To stop the sink before deletion if it's not used, we need to hold
+ // a ref to it.
+ if (!cache_iter->used) {
+ sink_to_stop = cache_iter->sink;
+ UMA_HISTOGRAM_BOOLEAN(
+ "Media.Audio.Render.SinkCache.InfoSinkReusedForOutput", false);
+ }
+
+ cache_.erase(cache_iter);
+ } // Lock scope;
+
+ // Stop the sink out of the lock scope.
+ if (sink_to_stop.get()) {
+ DCHECK_EQ(sink_ptr, sink_to_stop.get());
+ sink_to_stop->Stop();
+ }
+}
+
+AudioRendererSinkCache::CacheContainer::iterator
+AudioRendererSinkCache::FindCacheEntry_Locked(
+ const LocalFrameToken& source_frame_token,
+ const std::string& device_id,
+ bool unused_only) {
+ return std::find_if(
+ cache_.begin(), cache_.end(),
+ [source_frame_token, &device_id, unused_only](const CacheEntry& val) {
+ if (val.used && unused_only)
+ return false;
+ if (val.source_frame_token != source_frame_token)
+ return false;
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id) &&
+ media::AudioDeviceDescription::IsDefaultDevice(val.device_id)) {
+ // Both device IDs represent the same default device => do not
+ // compare them;
+ return true;
+ }
+ return val.device_id == device_id;
+ });
+}
+
+void AudioRendererSinkCache::CacheOrStopUnusedSink(
+ const LocalFrameToken& source_frame_token,
+ const std::string& device_id,
+ scoped_refptr<media::AudioRendererSink> sink) {
+ if (!SinkIsHealthy(sink.get())) {
+ TRACE_EVENT_INSTANT0("audio", "CacheOrStopUnusedSink: Unhealthy sink",
+ TRACE_EVENT_SCOPE_THREAD);
+ // Since |sink| is not cached, we must make sure to Stop it now.
+ sink->Stop();
+ return;
+ }
+
+ CacheEntry cache_entry = {source_frame_token, device_id, std::move(sink),
+ false /* not used */};
+
+ {
+ base::AutoLock auto_lock(cache_lock_);
+ cache_.push_back(cache_entry);
+ }
+
+ DeleteLaterIfUnused(cache_entry.sink.get());
+}
+
+void AudioRendererSinkCache::DropSinksForFrame(
+ const LocalFrameToken& source_frame_token) {
+ base::AutoLock auto_lock(cache_lock_);
+ base::EraseIf(cache_, [source_frame_token](const CacheEntry& val) {
+ if (val.source_frame_token == source_frame_token) {
+ val.sink->Stop();
+ return true;
+ }
+ return false;
+ });
+}
+
+size_t AudioRendererSinkCache::GetCacheSizeForTesting() {
+ return cache_.size();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h
new file mode 100644
index 00000000000..88335a899e2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h
@@ -0,0 +1,125 @@
+// 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_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "media/audio/audio_sink_parameters.h"
+#include "media/base/output_device_info.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace media {
+class AudioRendererSink;
+}
+
+namespace blink {
+
+class LocalFrame;
+
+// Caches AudioRendererSink instances, provides them to the clients for usage,
+// tracks their used/unused state, reuses them to obtain output device
+// information, garbage-collects unused sinks.
+// Must live on the main render thread. Thread safe.
+class MODULES_EXPORT AudioRendererSinkCache {
+ public:
+ class FrameObserver;
+
+ // Callback to be used for AudioRendererSink creation
+ using CreateSinkCallback =
+ base::RepeatingCallback<scoped_refptr<media::AudioRendererSink>(
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params)>;
+
+ // If called, the cache will drop sinks belonging to the specified frame on
+ // navigation.
+ static void InstallFrameObserver(LocalFrame& frame);
+
+ // |cleanup_task_runner| will be used to delete sinks when they are unused,
+ // AudioRendererSinkCache must outlive any tasks posted to it. Since
+ // the sink cache is normally a process-wide singleton, this isn't a problem.
+ AudioRendererSinkCache(
+ scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner,
+ CreateSinkCallback create_sink_callback,
+ base::TimeDelta delete_timeout);
+ ~AudioRendererSinkCache();
+
+ // AudioRendererSinkCache implementation:
+ media::OutputDeviceInfo GetSinkInfo(const LocalFrameToken& source_frame_token,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id);
+ scoped_refptr<media::AudioRendererSink> GetSink(
+ const LocalFrameToken& source_frame_token,
+ const std::string& device_id);
+ void ReleaseSink(const media::AudioRendererSink* sink_ptr);
+
+ private:
+ friend class AudioRendererSinkCacheTest;
+ friend class CacheEntryFinder;
+ friend class AudioRendererSinkCache::FrameObserver;
+
+ struct CacheEntry;
+ using CacheContainer = std::vector<CacheEntry>;
+
+ // Schedules a sink for deletion. Deletion will be performed on the same
+ // thread the cache is created on.
+ void DeleteLaterIfUnused(const media::AudioRendererSink* sink_ptr);
+
+ // Deletes a sink from the cache. If |force_delete_used| is set, a sink being
+ // deleted can (and should) be in use at the moment of deletion; otherwise the
+ // sink is deleted only if unused.
+ void DeleteSink(const media::AudioRendererSink* sink_ptr,
+ bool force_delete_used);
+
+ CacheContainer::iterator FindCacheEntry_Locked(
+ const LocalFrameToken& source_frame_token,
+ const std::string& device_id,
+ bool unused_only);
+
+ void CacheOrStopUnusedSink(const LocalFrameToken& source_frame_token,
+ const std::string& device_id,
+ scoped_refptr<media::AudioRendererSink> sink);
+
+ void DropSinksForFrame(const LocalFrameToken& source_frame_token);
+
+ // To avoid publishing CacheEntry structure in the header.
+ size_t GetCacheSizeForTesting();
+
+ // Global instance, set in constructor and unset in destructor.
+ static AudioRendererSinkCache* instance_;
+
+ // Renderer main task runner.
+ const scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner_;
+
+ // Callback used for sink creation.
+ const CreateSinkCallback create_sink_cb_;
+
+ // Cached sink deletion timeout.
+ // For example: (1) sink was created and cached in GetSinkInfo(), and then (2)
+ // the same sink is requested in GetSink(), if time interval between (1) and
+ // (2) is less than |kDeleteTimeoutMs|, then sink cached in (1) is reused in
+ // (2). On the other hand, if after (1) nobody is interested in the sink
+ // within |kDeleteTimeoutMs|, it is garbage-collected.
+ const base::TimeDelta delete_timeout_;
+
+ // Cached sinks, protected by lock.
+ base::Lock cache_lock_;
+ CacheContainer cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCache);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache_test.cc b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache_test.cc
new file mode 100644
index 00000000000..8da62ee15ba
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache_test.cc
@@ -0,0 +1,422 @@
+// 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/media/audio/audio_renderer_sink_cache.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/check.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/mock_audio_renderer_sink.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+const char* const kDefaultDeviceId =
+ media::AudioDeviceDescription::kDefaultDeviceId;
+const char kAnotherDeviceId[] = "another-device-id";
+const char kUnhealthyDeviceId[] = "i-am-sick";
+const LocalFrameToken kFrameToken;
+constexpr base::TimeDelta kDeleteTimeout =
+ base::TimeDelta::FromMilliseconds(500);
+} // namespace
+
+class AudioRendererSinkCacheTest : public testing::Test {
+ public:
+ AudioRendererSinkCacheTest()
+ : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::Time::Now(),
+ base::TimeTicks::Now())),
+ task_runner_context_(
+ std::make_unique<base::TestMockTimeTaskRunner::ScopedContext>(
+ task_runner_)),
+ cache_(std::make_unique<AudioRendererSinkCache>(
+ task_runner_,
+ base::BindRepeating(&AudioRendererSinkCacheTest::CreateSink,
+ base::Unretained(this)),
+ kDeleteTimeout)) {}
+ ~AudioRendererSinkCacheTest() override {
+ task_runner_->FastForwardUntilNoTasksRemain();
+ }
+
+ void GetSink(const LocalFrameToken& frame_token,
+ const std::string& device_id,
+ media::AudioRendererSink** sink) {
+ *sink = cache_->GetSink(frame_token, device_id).get();
+ }
+
+ protected:
+ int sink_count() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ return cache_->GetCacheSizeForTesting();
+ }
+
+ scoped_refptr<media::AudioRendererSink> CreateSink(
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ return new testing::NiceMock<media::MockAudioRendererSink>(
+ params.device_id, (params.device_id == kUnhealthyDeviceId)
+ ? media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL
+ : media::OUTPUT_DEVICE_STATUS_OK);
+ }
+
+ void ExpectNotToStop(media::AudioRendererSink* sink) {
+ // The sink must be stoped before deletion.
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink), Stop())
+ .Times(0);
+ }
+
+ // Posts the task to the specified thread and runs current message loop until
+ // the task is completed.
+ void PostAndWaitUntilDone(const base::Thread& thread,
+ base::OnceClosure task) {
+ base::WaitableEvent e{base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED};
+
+ thread.task_runner()->PostTask(FROM_HERE, std::move(task));
+ thread.task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&e)));
+
+ e.Wait();
+ }
+
+ void DropSinksForFrame(const LocalFrameToken& frame_token) {
+ cache_->DropSinksForFrame(frame_token);
+ }
+
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ // Ensure all things run on |task_runner_| instead of the default task
+ // runner initialized by blink_unittests.
+ std::unique_ptr<base::TestMockTimeTaskRunner::ScopedContext>
+ task_runner_context_;
+
+ std::unique_ptr<AudioRendererSinkCache> cache_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCacheTest);
+};
+
+// Verify that normal get/release sink sequence works.
+TEST_F(AudioRendererSinkCacheTest, GetReleaseSink) {
+ // Verify that a new sink is successfully created.
+ EXPECT_EQ(0, sink_count());
+ scoped_refptr<media::AudioRendererSink> sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ ExpectNotToStop(sink.get()); // Cache should not stop sinks marked as used.
+ EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(1, sink_count());
+
+ // Verify that another sink with the same key is successfully created
+ scoped_refptr<media::AudioRendererSink> another_sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ ExpectNotToStop(another_sink.get());
+ EXPECT_EQ(kDefaultDeviceId, another_sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(2, sink_count());
+ EXPECT_NE(sink, another_sink);
+
+ // Verify that another sink with a different kay is successfully created.
+ scoped_refptr<media::AudioRendererSink> yet_another_sink =
+ cache_->GetSink(kFrameToken, kAnotherDeviceId).get();
+ ExpectNotToStop(yet_another_sink.get());
+ EXPECT_EQ(kAnotherDeviceId,
+ yet_another_sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(3, sink_count());
+ EXPECT_NE(sink, yet_another_sink);
+ EXPECT_NE(another_sink, yet_another_sink);
+
+ // Verify that the first sink is successfully deleted.
+ cache_->ReleaseSink(sink.get());
+ EXPECT_EQ(2, sink_count());
+ sink = nullptr;
+
+ // Make sure we deleted the right sink, and the memory for the rest is not
+ // corrupted.
+ EXPECT_EQ(kDefaultDeviceId, another_sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(kAnotherDeviceId,
+ yet_another_sink->GetOutputDeviceInfo().device_id());
+
+ // Verify that the second sink is successfully deleted.
+ cache_->ReleaseSink(another_sink.get());
+ EXPECT_EQ(1, sink_count());
+ EXPECT_EQ(kAnotherDeviceId,
+ yet_another_sink->GetOutputDeviceInfo().device_id());
+
+ cache_->ReleaseSink(yet_another_sink.get());
+ EXPECT_EQ(0, sink_count());
+}
+
+// Verify that the sink created with GetSinkInfo() is reused when possible.
+TEST_F(AudioRendererSinkCacheTest, GetDeviceInfo) {
+ EXPECT_EQ(0, sink_count());
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count());
+
+ // The info on the same device is requested, so no new sink is created.
+ media::OutputDeviceInfo one_more_device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count());
+ EXPECT_EQ(device_info.device_id(), one_more_device_info.device_id());
+
+ // Aquire the sink that was created on GetSinkInfo().
+ scoped_refptr<media::AudioRendererSink> sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ EXPECT_EQ(1, sink_count());
+ EXPECT_EQ(device_info.device_id(), sink->GetOutputDeviceInfo().device_id());
+
+ // Now the sink is in used, but we can still get the device info out of it, no
+ // new sink is created.
+ one_more_device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count());
+ EXPECT_EQ(device_info.device_id(), one_more_device_info.device_id());
+
+ // Request sink for the same device. The first sink is in use, so a new one
+ // should be created.
+ scoped_refptr<media::AudioRendererSink> another_sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ EXPECT_EQ(2, sink_count());
+ EXPECT_EQ(device_info.device_id(),
+ another_sink->GetOutputDeviceInfo().device_id());
+}
+
+// Verify that the sink created with GetSinkInfo() is deleted if unused.
+TEST_F(AudioRendererSinkCacheTest, GarbageCollection) {
+ EXPECT_EQ(0, sink_count());
+
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count());
+
+ media::OutputDeviceInfo another_device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kAnotherDeviceId);
+ EXPECT_EQ(2, sink_count());
+
+ // Wait for garbage collection. Doesn't actually sleep, just advances the mock
+ // clock.
+ task_runner_->FastForwardBy(kDeleteTimeout);
+
+ // All the sinks should be garbage-collected by now.
+ EXPECT_EQ(0, sink_count());
+}
+
+// Verify that the sink created with GetSinkInfo() is not deleted if used within
+// the timeout.
+TEST_F(AudioRendererSinkCacheTest, NoGarbageCollectionForUsedSink) {
+ EXPECT_EQ(0, sink_count());
+
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count());
+
+ // Wait less than garbage collection timeout.
+ base::TimeDelta wait_a_bit =
+ kDeleteTimeout - base::TimeDelta::FromMilliseconds(1);
+ task_runner_->FastForwardBy(wait_a_bit);
+
+ // Sink is not deleted yet.
+ EXPECT_EQ(1, sink_count());
+
+ // Request it:
+ scoped_refptr<media::AudioRendererSink> sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(1, sink_count());
+
+ // Wait more to hit garbage collection timeout.
+ task_runner_->FastForwardBy(kDeleteTimeout);
+
+ // The sink is still in place.
+ EXPECT_EQ(1, sink_count());
+}
+
+// Verify that the sink created with GetSinkInfo() is not cached if it is
+// unhealthy.
+TEST_F(AudioRendererSinkCacheTest, UnhealthySinkIsNotCached) {
+ EXPECT_EQ(0, sink_count());
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kUnhealthyDeviceId);
+ EXPECT_EQ(0, sink_count());
+ scoped_refptr<media::AudioRendererSink> sink =
+ cache_->GetSink(kFrameToken, kUnhealthyDeviceId).get();
+ EXPECT_EQ(0, sink_count());
+}
+
+// Verify that a sink created with GetSinkInfo() is stopped even if it's
+// unhealthy.
+TEST_F(AudioRendererSinkCacheTest, UnhealthySinkIsStopped) {
+ scoped_refptr<media::MockAudioRendererSink> sink =
+ new media::MockAudioRendererSink(
+ kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
+
+ cache_.reset(); // Destruct first so there's only one cache at a time.
+ cache_ = std::make_unique<AudioRendererSinkCache>(
+ task_runner_,
+ base::BindRepeating(
+ [](scoped_refptr<media::AudioRendererSink> sink,
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ EXPECT_EQ(kFrameToken, frame_token);
+ EXPECT_TRUE(params.session_id.is_empty());
+ EXPECT_EQ(kUnhealthyDeviceId, params.device_id);
+ return sink;
+ },
+ sink),
+ kDeleteTimeout);
+
+ EXPECT_CALL(*sink, Stop());
+
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kUnhealthyDeviceId);
+}
+
+// Verify that a sink created with GetSinkInfo() is stopped even if it's
+// unhealthy.
+TEST_F(AudioRendererSinkCacheTest, UnhealthySinkUsingSessionIdIsStopped) {
+ scoped_refptr<media::MockAudioRendererSink> sink =
+ new media::MockAudioRendererSink(
+ kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
+
+ cache_.reset(); // Destruct first so there's only one cache at a time.
+ cache_ = std::make_unique<AudioRendererSinkCache>(
+ task_runner_,
+ base::BindRepeating(
+ [](scoped_refptr<media::AudioRendererSink> sink,
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ EXPECT_EQ(kFrameToken, frame_token);
+ EXPECT_TRUE(!params.session_id.is_empty());
+ EXPECT_TRUE(params.device_id.empty());
+ return sink;
+ },
+ sink),
+ kDeleteTimeout);
+
+ EXPECT_CALL(*sink, Stop());
+
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken::Create(), std::string());
+}
+
+// Verify that cache works fine if a sink scheduled for deletion is acquired and
+// released before deletion timeout elapses.
+TEST_F(AudioRendererSinkCacheTest, ReleaseSinkBeforeScheduledDeletion) {
+ EXPECT_EQ(0, sink_count());
+
+ base::Thread thread("timeout_thread");
+ thread.Start();
+
+ media::OutputDeviceInfo device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kDefaultDeviceId);
+ EXPECT_EQ(1, sink_count()); // This sink is scheduled for deletion now.
+
+ // Request it:
+ scoped_refptr<media::AudioRendererSink> sink =
+ cache_->GetSink(kFrameToken, kDefaultDeviceId).get();
+ ExpectNotToStop(sink.get());
+ EXPECT_EQ(1, sink_count());
+
+ // Release it:
+ cache_->ReleaseSink(sink.get());
+ EXPECT_EQ(0, sink_count());
+
+ media::OutputDeviceInfo another_device_info = cache_->GetSinkInfo(
+ kFrameToken, base::UnguessableToken(), kAnotherDeviceId);
+ EXPECT_EQ(1, sink_count()); // This sink is scheduled for deletion now.
+
+ task_runner_->FastForwardBy(kDeleteTimeout);
+
+ // Nothing crashed and the second sink deleted on schedule.
+ EXPECT_EQ(0, sink_count());
+}
+
+// Check that a sink created on one thread in response to GetSinkInfo can be
+// used on another thread.
+TEST_F(AudioRendererSinkCacheTest, MultithreadedAccess) {
+ EXPECT_EQ(0, sink_count());
+
+ base::Thread thread1("thread1");
+ thread1.Start();
+
+ base::Thread thread2("thread2");
+ thread2.Start();
+
+ // Request device information on the first thread.
+ PostAndWaitUntilDone(
+ thread1,
+ base::BindOnce(base::IgnoreResult(&AudioRendererSinkCache::GetSinkInfo),
+ base::Unretained(cache_.get()), kFrameToken,
+ base::UnguessableToken(), kDefaultDeviceId));
+
+ EXPECT_EQ(1, sink_count());
+
+ // Request the sink on the second thread.
+ media::AudioRendererSink* sink;
+
+ PostAndWaitUntilDone(thread2,
+ base::BindOnce(&AudioRendererSinkCacheTest::GetSink,
+ base::Unretained(this), kFrameToken,
+ kDefaultDeviceId, &sink));
+
+ EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id());
+ EXPECT_EQ(1, sink_count());
+
+ // Request device information on the first thread again.
+ PostAndWaitUntilDone(
+ thread1,
+ base::BindOnce(base::IgnoreResult(&AudioRendererSinkCache::GetSinkInfo),
+ base::Unretained(cache_.get()), kFrameToken,
+ base::UnguessableToken(), kDefaultDeviceId));
+ EXPECT_EQ(1, sink_count());
+
+ // Release the sink on the second thread.
+ PostAndWaitUntilDone(
+ thread2,
+ base::BindOnce(&AudioRendererSinkCache::ReleaseSink,
+ base::Unretained(cache_.get()), base::RetainedRef(sink)));
+
+ EXPECT_EQ(0, sink_count());
+}
+
+TEST_F(AudioRendererSinkCacheTest, StopsAndDropsSinks) {
+ EXPECT_EQ(0, sink_count());
+ scoped_refptr<media::AudioRendererSink> sink1 =
+ cache_->GetSink(kFrameToken, "device1").get();
+ scoped_refptr<media::AudioRendererSink> sink2 =
+ cache_->GetSink(kFrameToken, "device2").get();
+ EXPECT_EQ(2, sink_count());
+
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink1.get()), Stop());
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink2.get()), Stop());
+ DropSinksForFrame(kFrameToken);
+ EXPECT_EQ(0, sink_count());
+}
+
+TEST_F(AudioRendererSinkCacheTest, StopsAndDropsCorrectSinks) {
+ EXPECT_EQ(0, sink_count());
+ scoped_refptr<media::AudioRendererSink> sink1 =
+ cache_->GetSink(kFrameToken, "device1").get();
+ scoped_refptr<media::AudioRendererSink> another_sink =
+ cache_->GetSink(LocalFrameToken(), "device1").get();
+ scoped_refptr<media::AudioRendererSink> sink2 =
+ cache_->GetSink(kFrameToken, "device2").get();
+ EXPECT_EQ(3, sink_count());
+
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink1.get()), Stop());
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink2.get()), Stop());
+ DropSinksForFrame(kFrameToken);
+ EXPECT_EQ(1, sink_count());
+ EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(another_sink.get()),
+ Stop());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/fuchsia_audio_device_factory.cc b/chromium/third_party/blink/renderer/modules/media/audio/fuchsia_audio_device_factory.cc
new file mode 100644
index 00000000000..3043b6726e1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/fuchsia_audio_device_factory.cc
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/web/modules/media/audio/fuchsia_audio_device_factory.h"
+
+#include <fuchsia/media/cpp/fidl.h>
+
+#include "media/base/audio_renderer_sink.h"
+#include "media/fuchsia/audio/fuchsia_audio_capturer_source.h"
+#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom-blink.h"
+#include "media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+
+namespace blink {
+
+FuchsiaAudioDeviceFactory::FuchsiaAudioDeviceFactory() = default;
+FuchsiaAudioDeviceFactory::~FuchsiaAudioDeviceFactory() = default;
+
+scoped_refptr<media::AudioRendererSink>
+FuchsiaAudioDeviceFactory::CreateFinalAudioRendererSink(
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params,
+ base::TimeDelta auth_timeout) {
+ // Return nullptr to fallback to the default renderer implementation.
+ return nullptr;
+}
+
+scoped_refptr<media::AudioRendererSink>
+FuchsiaAudioDeviceFactory::CreateAudioRendererSink(
+ WebAudioDeviceSourceType source_type,
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ // Return nullptr to fallback to the default renderer implementation.
+ return nullptr;
+}
+
+scoped_refptr<media::SwitchableAudioRendererSink>
+FuchsiaAudioDeviceFactory::CreateSwitchableAudioRendererSink(
+ WebAudioDeviceSourceType source_type,
+ const LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ // Return nullptr to fallback to the default renderer implementation.
+ return nullptr;
+}
+
+scoped_refptr<media::AudioCapturerSource>
+FuchsiaAudioDeviceFactory::CreateAudioCapturerSource(
+ const LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& params) {
+ auto* local_frame = LocalFrame::FromFrameToken(frame_token);
+ if (!local_frame)
+ return nullptr;
+
+ // Connect FuchsiaMediaResourceProvider.
+ mojo::Remote<media::mojom::blink::FuchsiaMediaResourceProvider>
+ media_resource_provider;
+ local_frame->GetBrowserInterfaceBroker().GetInterface(
+ media_resource_provider.BindNewPipeAndPassReceiver());
+
+ // Connect AudioCapturer.
+ fidl::InterfaceHandle<fuchsia::media::AudioCapturer> capturer;
+ media_resource_provider->CreateAudioCapturer(capturer.NewRequest());
+
+ return base::MakeRefCounted<media::FuchsiaAudioCapturerSource>(
+ std::move(capturer));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.cc b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.cc
new file mode 100644
index 00000000000..d715688fd41
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.cc
@@ -0,0 +1,123 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/metrics/histogram_macros.h"
+#include "media/audio/audio_device_description.h"
+#include "media/mojo/mojom/audio_data_pipe.mojom-blink.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace blink {
+
+MojoAudioInputIPC::MojoAudioInputIPC(
+ const media::AudioSourceParameters& source_params,
+ StreamCreatorCB stream_creator,
+ StreamAssociatorCB stream_associator)
+ : source_params_(source_params),
+ stream_creator_(std::move(stream_creator)),
+ stream_associator_(std::move(stream_associator)) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ DCHECK(stream_creator_);
+ DCHECK(stream_associator_);
+}
+
+MojoAudioInputIPC::~MojoAudioInputIPC() = default;
+
+void MojoAudioInputIPC::CreateStream(media::AudioInputIPCDelegate* delegate,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(delegate);
+ DCHECK(!delegate_);
+
+ delegate_ = delegate;
+
+ mojo::PendingRemote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ client;
+ factory_client_receiver_.Bind(client.InitWithNewPipeAndPassReceiver());
+ factory_client_receiver_.set_disconnect_handler(base::BindOnce(
+ &media::AudioInputIPCDelegate::OnError, base::Unretained(delegate_)));
+
+ stream_creator_.Run(source_params_, std::move(client), params,
+ automatic_gain_control, total_segments);
+}
+
+void MojoAudioInputIPC::RecordStream() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(stream_.is_bound());
+ stream_->Record();
+}
+
+void MojoAudioInputIPC::SetVolume(double volume) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(stream_.is_bound());
+ stream_->SetVolume(volume);
+}
+
+void MojoAudioInputIPC::SetOutputDeviceForAec(
+ const std::string& output_device_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(stream_) << "Can only be called after the stream has been created";
+ // Loopback streams have no stream ids and cannot be use echo cancellation
+ if (stream_id_.has_value())
+ stream_associator_.Run(*stream_id_, output_device_id);
+}
+
+void MojoAudioInputIPC::CloseStream() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ delegate_ = nullptr;
+ factory_client_receiver_.reset();
+ stream_client_receiver_.reset();
+ stream_.reset();
+}
+
+void MojoAudioInputIPC::StreamCreated(
+ mojo::PendingRemote<media::mojom::blink::AudioInputStream> stream,
+ mojo::PendingReceiver<media::mojom::blink::AudioInputStreamClient>
+ stream_client_receiver,
+ media::mojom::blink::ReadOnlyAudioDataPipePtr data_pipe,
+ bool initially_muted,
+ const base::Optional<base::UnguessableToken>& stream_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(delegate_);
+ DCHECK(!stream_);
+ DCHECK(!stream_client_receiver_.is_bound());
+
+ stream_.Bind(std::move(stream));
+ stream_client_receiver_.Bind(std::move(stream_client_receiver));
+
+ // Keep the stream_id, if we get one. Regular input stream have stream ids,
+ // but Loopback streams do not.
+ stream_id_ = stream_id;
+
+ DCHECK(data_pipe->socket.is_valid_platform_file());
+ base::ScopedPlatformFile socket_handle = data_pipe->socket.TakePlatformFile();
+
+ base::ReadOnlySharedMemoryRegion& shared_memory_region =
+ data_pipe->shared_memory;
+ DCHECK(shared_memory_region.IsValid());
+
+ delegate_->OnStreamCreated(std::move(shared_memory_region),
+ std::move(socket_handle), initially_muted);
+}
+
+void MojoAudioInputIPC::OnError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(delegate_);
+ delegate_->OnError();
+}
+
+void MojoAudioInputIPC::OnMutedStateChanged(bool is_muted) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(delegate_);
+ delegate_->OnMuted(is_muted);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h
new file mode 100644
index 00000000000..5db99495593
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h
@@ -0,0 +1,99 @@
+// Copyright 2017 The Chromium Authors. 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_MEDIA_AUDIO_MOJO_AUDIO_INPUT_IPC_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_MOJO_AUDIO_INPUT_IPC_H_
+
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/time/time.h"
+#include "media/audio/audio_input_ipc.h"
+#include "media/audio/audio_source_parameters.h"
+#include "media/mojo/mojom/audio_input_stream.mojom-blink.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom-blink.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+// MojoAudioInputIPC is a renderer-side class for handling creation,
+// initialization and control of an input stream. May only be used on a single
+// thread.
+class MODULES_EXPORT MojoAudioInputIPC
+ : public media::AudioInputIPC,
+ public mojom::blink::RendererAudioInputStreamFactoryClient,
+ public media::mojom::blink::AudioInputStreamClient {
+ public:
+ // This callback is used by MojoAudioInputIPC to create streams.
+ // It is expected that after calling, either client->StreamCreated() is
+ // called or |client| is destructed.
+ using StreamCreatorCB = base::RepeatingCallback<void(
+ const media::AudioSourceParameters& source_params,
+ mojo::PendingRemote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ client,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments)>;
+
+ using StreamAssociatorCB =
+ base::RepeatingCallback<void(const base::UnguessableToken& stream_id,
+ const std::string& output_device_id)>;
+
+ MojoAudioInputIPC(const media::AudioSourceParameters& source_params,
+ StreamCreatorCB stream_creator,
+ StreamAssociatorCB stream_associator);
+ ~MojoAudioInputIPC() override;
+
+ // AudioInputIPC implementation
+ void CreateStream(media::AudioInputIPCDelegate* delegate,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments) override;
+
+ void RecordStream() override;
+ void SetVolume(double volume) override;
+ void SetOutputDeviceForAec(const std::string& output_device_id) override;
+ void CloseStream() override;
+
+ private:
+ void StreamCreated(
+ mojo::PendingRemote<media::mojom::blink::AudioInputStream> stream,
+ mojo::PendingReceiver<media::mojom::blink::AudioInputStreamClient>
+ stream_client_receiver,
+ media::mojom::blink::ReadOnlyAudioDataPipePtr data_pipe,
+ bool initially_muted,
+ const base::Optional<base::UnguessableToken>& stream_id) override;
+ void OnError() override;
+ void OnMutedStateChanged(bool is_muted) override;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ const media::AudioSourceParameters source_params_;
+
+ StreamCreatorCB stream_creator_;
+ StreamAssociatorCB stream_associator_;
+
+ mojo::Remote<media::mojom::blink::AudioInputStream> stream_;
+ // Initialized on StreamCreated.
+ base::Optional<base::UnguessableToken> stream_id_;
+ mojo::Receiver<AudioInputStreamClient> stream_client_receiver_{this};
+ mojo::Receiver<mojom::blink::RendererAudioInputStreamFactoryClient>
+ factory_client_receiver_{this};
+ media::AudioInputIPCDelegate* delegate_ = nullptr;
+
+ base::WeakPtrFactory<MojoAudioInputIPC> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(MojoAudioInputIPC);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_MOJO_AUDIO_INPUT_IPC_H_
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc_test.cc b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc_test.cc
new file mode 100644
index 00000000000..acbbbffe035
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc_test.cc
@@ -0,0 +1,321 @@
+// Copyright 2017 The Chromium Authors. 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/media/audio/mojo_audio_input_ipc.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/gtest_util.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_parameters.h"
+#include "media/mojo/mojom/audio_data_pipe.mojom-blink.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Invoke;
+using testing::Mock;
+using testing::StrictMock;
+
+namespace blink {
+
+namespace {
+
+const size_t kMemoryLength = 4321;
+const size_t kTotalSegments = 1;
+const double kNewVolume = 0.271828;
+const char kOutputDeviceId[] = "2345";
+
+media::AudioParameters Params() {
+ return media::AudioParameters::UnavailableDeviceParams();
+}
+
+media::AudioSourceParameters SourceParams() {
+ return media::AudioSourceParameters(
+ base::UnguessableToken::Deserialize(1234, 5678));
+}
+
+class MockStream : public media::mojom::blink::AudioInputStream {
+ public:
+ MOCK_METHOD0(Record, void());
+ MOCK_METHOD1(SetVolume, void(double));
+};
+
+class MockDelegate : public media::AudioInputIPCDelegate {
+ public:
+ MockDelegate() = default;
+ ~MockDelegate() override = default;
+
+ void OnStreamCreated(base::ReadOnlySharedMemoryRegion mem_handle,
+ base::SyncSocket::ScopedHandle socket_handle,
+ bool initially_muted) override {
+ GotOnStreamCreated(initially_muted);
+ }
+
+ MOCK_METHOD1(GotOnStreamCreated, void(bool initially_muted));
+ MOCK_METHOD0(OnError, void());
+ MOCK_METHOD1(OnMuted, void(bool));
+ MOCK_METHOD0(OnIPCClosed, void());
+};
+
+class FakeStreamCreator {
+ public:
+ FakeStreamCreator(media::mojom::blink::AudioInputStream* stream,
+ bool initially_muted)
+ : stream_(stream),
+ receiver_(stream_),
+ initially_muted_(initially_muted) {}
+
+ void Create(
+ const media::AudioSourceParameters& source_params,
+ mojo::PendingRemote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ factory_client,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments) {
+ EXPECT_FALSE(receiver_.is_bound());
+ EXPECT_NE(stream_, nullptr);
+ EXPECT_EQ(source_params.session_id, SourceParams().session_id);
+ factory_client_.reset();
+ factory_client_.Bind(std::move(factory_client));
+ base::CancelableSyncSocket foreign_socket;
+ EXPECT_TRUE(
+ base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
+ factory_client_->StreamCreated(
+ receiver_.BindNewPipeAndPassRemote(),
+ stream_client_.BindNewPipeAndPassReceiver(),
+ {base::in_place,
+ base::ReadOnlySharedMemoryRegion::Create(kMemoryLength).region,
+ mojo::PlatformHandle(foreign_socket.Take())},
+ initially_muted_, base::UnguessableToken::Create());
+ }
+
+ MojoAudioInputIPC::StreamCreatorCB GetCallback() {
+ return base::BindRepeating(&FakeStreamCreator::Create,
+ base::Unretained(this));
+ }
+
+ void Rearm() {
+ stream_client_.reset();
+ receiver_.reset();
+ socket_.Close();
+ }
+
+ void SignalError() {
+ ASSERT_TRUE(stream_client_);
+ stream_client_->OnError();
+ }
+
+ private:
+ media::mojom::blink::AudioInputStream* stream_;
+ mojo::Remote<media::mojom::blink::AudioInputStreamClient> stream_client_;
+ mojo::Remote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ factory_client_;
+ mojo::Receiver<media::mojom::blink::AudioInputStream> receiver_;
+ bool initially_muted_;
+ base::CancelableSyncSocket socket_;
+};
+
+void AssociateOutputForAec(const base::UnguessableToken& stream_id,
+ const std::string& output_device_id) {
+ EXPECT_FALSE(stream_id.is_empty());
+ EXPECT_EQ(output_device_id, kOutputDeviceId);
+}
+
+} // namespace
+
+TEST(MojoAudioInputIPC, OnStreamCreated_Propagates) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(false));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioInputIPC, FactoryDisconnected_SendsError) {
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(),
+ base::BindRepeating(
+ [](const media::AudioSourceParameters&,
+ mojo::PendingRemote<
+ mojom::blink::RendererAudioInputStreamFactoryClient>
+ factory_client,
+ const media::AudioParameters& params,
+ bool automatic_gain_control, uint32_t total_segments) {}),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, OnError());
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioInputIPC, OnStreamCreated_PropagatesInitiallyMuted) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, true);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(true));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioInputIPC, IsReusable) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ for (int i = 0; i < 5; ++i) {
+ creator.Rearm();
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(_));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
+TEST(MojoAudioInputIPC, IsReusableAfterError) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ for (int i = 0; i < 5; ++i) {
+ creator.Rearm();
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(_));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ EXPECT_CALL(delegate, OnError());
+ creator.SignalError();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
+TEST(MojoAudioInputIPC, Record_Records) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(_));
+ EXPECT_CALL(stream, Record());
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+ ipc->RecordStream();
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioInputIPC, SetVolume_SetsVolume) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(_));
+ EXPECT_CALL(stream, SetVolume(kNewVolume));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+ ipc->SetVolume(kNewVolume);
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioInputIPC, SetOutputDeviceForAec_AssociatesInputAndOutputForAec) {
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ FakeStreamCreator creator(&stream, false);
+
+ const std::unique_ptr<media::AudioInputIPC> ipc =
+ std::make_unique<MojoAudioInputIPC>(
+ SourceParams(), creator.GetCallback(),
+ base::BindRepeating(&AssociateOutputForAec));
+
+ EXPECT_CALL(delegate, GotOnStreamCreated(_));
+
+ ipc->CreateStream(&delegate, Params(), false, kTotalSegments);
+ base::RunLoop().RunUntilIdle();
+ ipc->SetOutputDeviceForAec(kOutputDeviceId);
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.cc b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.cc
new file mode 100644
index 00000000000..e4b4cf29316
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.cc
@@ -0,0 +1,254 @@
+// Copyright 2017 The Chromium Authors. 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/media/audio/mojo_audio_output_ipc.h"
+
+#include <utility>
+
+#include "base/metrics/histogram_macros.h"
+#include "media/audio/audio_device_description.h"
+#include "media/mojo/mojom/audio_output_stream.mojom-blink.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
+
+namespace blink {
+
+namespace {
+
+void TrivialAuthorizedCallback(media::mojom::blink::OutputDeviceStatus,
+ const media::AudioParameters&,
+ const String&) {}
+
+} // namespace
+
+MojoAudioOutputIPC::MojoAudioOutputIPC(
+ FactoryAccessorCB factory_accessor,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : factory_accessor_(std::move(factory_accessor)),
+ io_task_runner_(std::move(io_task_runner)) {}
+
+MojoAudioOutputIPC::~MojoAudioOutputIPC() {
+ DCHECK(!AuthorizationRequested() && !StreamCreationRequested())
+ << "CloseStream must be called before destructing the AudioOutputIPC";
+ // No sequence check.
+ // Destructing |weak_factory_| on any sequence is safe since it's not used
+ // after the final call to CloseStream, where its pointers are invalidated.
+}
+
+void MojoAudioOutputIPC::RequestDeviceAuthorization(
+ media::AudioOutputIPCDelegate* delegate,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(delegate);
+ DCHECK(!delegate_);
+ DCHECK(!AuthorizationRequested());
+ DCHECK(!StreamCreationRequested());
+ delegate_ = delegate;
+
+ // We wrap the callback in a WrapCallbackWithDefaultInvokeIfNotRun to detect
+ // the case when the mojo connection is terminated prior to receiving the
+ // response. In this case, the callback runner will be destructed and call
+ // ReceivedDeviceAuthorization with an error.
+ DoRequestDeviceAuthorization(
+ session_id, device_id,
+ mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+ WTF::Bind(&MojoAudioOutputIPC::ReceivedDeviceAuthorization,
+ weak_factory_.GetWeakPtr(), base::TimeTicks::Now()),
+ static_cast<media::mojom::blink::OutputDeviceStatus>(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL),
+ media::AudioParameters::UnavailableDeviceParams(), String()));
+}
+
+void MojoAudioOutputIPC::CreateStream(
+ media::AudioOutputIPCDelegate* delegate,
+ const media::AudioParameters& params,
+ const base::Optional<base::UnguessableToken>& processing_id) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(delegate);
+ DCHECK(!StreamCreationRequested());
+ if (!AuthorizationRequested()) {
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+ // No authorization requested yet. Request one for the default device.
+ // Since the delegate didn't explicitly request authorization, we shouldn't
+ // send a callback to it.
+ DoRequestDeviceAuthorization(
+ /*session_id=*/base::UnguessableToken(),
+ media::AudioDeviceDescription::kDefaultDeviceId,
+ WTF::Bind(&TrivialAuthorizedCallback));
+ }
+
+ DCHECK_EQ(delegate_, delegate);
+ // Since the creation callback won't fire if the provider receiver is gone
+ // and |this| owns |stream_provider_|, unretained is safe.
+ mojo::PendingRemote<media::mojom::blink::AudioOutputStreamProviderClient>
+ client_remote;
+ receiver_.Bind(client_remote.InitWithNewPipeAndPassReceiver());
+ // Unretained is safe because |this| owns |receiver_|.
+ receiver_.set_disconnect_with_reason_handler(
+ WTF::Bind(&MojoAudioOutputIPC::ProviderClientBindingDisconnected,
+ WTF::Unretained(this)));
+ stream_provider_->Acquire(params, std::move(client_remote));
+}
+
+void MojoAudioOutputIPC::PlayStream() {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ expected_state_ = kPlaying;
+ if (stream_.is_bound())
+ stream_->Play();
+}
+
+void MojoAudioOutputIPC::PauseStream() {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ expected_state_ = kPaused;
+ if (stream_.is_bound())
+ stream_->Pause();
+}
+
+void MojoAudioOutputIPC::FlushStream() {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ if (stream_.is_bound())
+ stream_->Flush();
+}
+
+void MojoAudioOutputIPC::CloseStream() {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ stream_provider_.reset();
+ stream_.reset();
+ receiver_.reset();
+ delegate_ = nullptr;
+ expected_state_ = kPaused;
+ volume_ = base::nullopt;
+
+ // Cancel any pending callbacks for this stream.
+ weak_factory_.InvalidateWeakPtrs();
+}
+
+void MojoAudioOutputIPC::SetVolume(double volume) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ volume_ = volume;
+ if (stream_.is_bound())
+ stream_->SetVolume(volume);
+ // else volume is set when the stream is created.
+}
+
+void MojoAudioOutputIPC::ProviderClientBindingDisconnected(
+ uint32_t disconnect_reason,
+ const std::string& description) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(delegate_);
+ if (disconnect_reason ==
+ static_cast<uint32_t>(media::mojom::blink::AudioOutputStreamObserver::
+ DisconnectReason::kPlatformError)) {
+ delegate_->OnError();
+ }
+ // Otherwise, disconnection was due to the frame owning |this| being
+ // destructed or having a navigation. In this case, |this| will soon be
+ // cleaned up.
+}
+
+bool MojoAudioOutputIPC::AuthorizationRequested() const {
+ return stream_provider_.is_bound();
+}
+
+bool MojoAudioOutputIPC::StreamCreationRequested() const {
+ return receiver_.is_bound();
+}
+
+mojo::PendingReceiver<media::mojom::blink::AudioOutputStreamProvider>
+MojoAudioOutputIPC::MakeProviderReceiver() {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(!AuthorizationRequested());
+
+ // Don't set a connection error handler.
+ // There are three possible reasons for a connection error.
+ // 1. The connection is broken before authorization was completed. In this
+ // case, the WrapCallbackWithDefaultInvokeIfNotRun wrapping the callback
+ // will call the callback with failure.
+ // 2. The connection is broken due to authorization being denied. In this
+ // case, the callback was called with failure first, so the state of the
+ // stream provider is irrelevant.
+ // 3. The connection was broken after authorization succeeded. This is because
+ // of the frame owning this stream being destructed, and this object will
+ // be cleaned up soon.
+ return stream_provider_.BindNewPipeAndPassReceiver();
+}
+
+void MojoAudioOutputIPC::DoRequestDeviceAuthorization(
+ const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ AuthorizationCB callback) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ auto* factory = factory_accessor_.Run();
+ if (!factory) {
+ LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";
+
+ // Create a provider receiver for consistency with the normal case.
+ MakeProviderReceiver();
+ // Resetting the callback asynchronously ensures consistent behaviour with
+ // when the factory is destroyed before reply, i.e. calling
+ // OnDeviceAuthorized with ERROR_INTERNAL in the normal case.
+ // The AudioOutputIPCDelegate will call CloseStream as necessary.
+ io_task_runner_->PostTask(
+ FROM_HERE, WTF::Bind([](AuthorizationCB cb) {}, std::move(callback)));
+ return;
+ }
+
+ static_assert(sizeof(int) == sizeof(int32_t),
+ "sizeof(int) == sizeof(int32_t)");
+ factory->RequestDeviceAuthorization(
+ MakeProviderReceiver(),
+ session_id.is_empty() ? base::Optional<base::UnguessableToken>()
+ : session_id,
+ String::FromUTF8(device_id), std::move(callback));
+}
+
+void MojoAudioOutputIPC::ReceivedDeviceAuthorization(
+ base::TimeTicks auth_start_time,
+ media::mojom::blink::OutputDeviceStatus status,
+ const media::AudioParameters& params,
+ const String& device_id) const {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(delegate_);
+
+ // Times over 15 s should be very rare, so we don't lose interesting data by
+ // making it the upper limit.
+ UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.Render.OutputDeviceAuthorizationTime",
+ base::TimeTicks::Now() - auth_start_time,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(15), 100);
+
+ delegate_->OnDeviceAuthorized(static_cast<media::OutputDeviceStatus>(status),
+ params, device_id.Utf8());
+}
+
+void MojoAudioOutputIPC::Created(
+ mojo::PendingRemote<media::mojom::blink::AudioOutputStream> pending_stream,
+ media::mojom::blink::ReadWriteAudioDataPipePtr data_pipe) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(delegate_);
+
+ stream_.reset();
+ stream_.Bind(std::move(pending_stream));
+
+ DCHECK(data_pipe->socket.is_valid_platform_file());
+ base::ScopedPlatformFile socket_handle = data_pipe->socket.TakePlatformFile();
+
+ base::UnsafeSharedMemoryRegion& shared_memory_region =
+ data_pipe->shared_memory;
+ DCHECK(shared_memory_region.IsValid());
+
+ delegate_->OnStreamCreated(std::move(shared_memory_region),
+ std::move(socket_handle),
+ expected_state_ == kPlaying);
+
+ if (volume_)
+ stream_->SetVolume(*volume_);
+ if (expected_state_ == kPlaying)
+ stream_->Play();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h
new file mode 100644
index 00000000000..475e75a9969
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h
@@ -0,0 +1,116 @@
+// Copyright 2017 The Chromium Authors. 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_MEDIA_AUDIO_MOJO_AUDIO_OUTPUT_IPC_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_MOJO_AUDIO_OUTPUT_IPC_H_
+
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "media/audio/audio_output_ipc.h"
+#include "media/mojo/mojom/audio_data_pipe.mojom-blink.h"
+#include "media/mojo/mojom/audio_output_stream.mojom-blink.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom-blink.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+// MojoAudioOutputIPC is a renderer-side class for handling creation,
+// initialization and control of an output stream. May only be used on a single
+// thread.
+class MODULES_EXPORT MojoAudioOutputIPC
+ : public media::AudioOutputIPC,
+ public media::mojom::blink::AudioOutputStreamProviderClient {
+ public:
+ using FactoryAccessorCB = base::RepeatingCallback<
+ blink::mojom::blink::RendererAudioOutputStreamFactory*()>;
+
+ // |factory_accessor| is required to provide a
+ // RendererAudioOutputStreamFactory* if IPC is possible.
+ MojoAudioOutputIPC(
+ FactoryAccessorCB factory_accessor,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+
+ ~MojoAudioOutputIPC() override;
+
+ // AudioOutputIPC implementation.
+ void RequestDeviceAuthorization(media::AudioOutputIPCDelegate* delegate,
+ const base::UnguessableToken& session_id,
+ const std::string& device_id) override;
+ void CreateStream(
+ media::AudioOutputIPCDelegate* delegate,
+ const media::AudioParameters& params,
+ const base::Optional<base::UnguessableToken>& processing_id) override;
+ void PlayStream() override;
+ void PauseStream() override;
+ void FlushStream() override;
+ void CloseStream() override;
+ void SetVolume(double volume) override;
+
+ // media::mojom::AudioOutputStreamProviderClient implementation.
+ void Created(
+ mojo::PendingRemote<media::mojom::blink::AudioOutputStream> stream,
+ media::mojom::blink::ReadWriteAudioDataPipePtr data_pipe) override;
+
+ private:
+ static constexpr double kDefaultVolume = 1.0;
+
+ using AuthorizationCB = blink::mojom::blink::
+ RendererAudioOutputStreamFactory::RequestDeviceAuthorizationCallback;
+
+ bool AuthorizationRequested() const;
+ bool StreamCreationRequested() const;
+
+ void ProviderClientBindingDisconnected(uint32_t disconnect_reason,
+ const std::string& description);
+
+ mojo::PendingReceiver<media::mojom::blink::AudioOutputStreamProvider>
+ MakeProviderReceiver();
+
+ // Tries to acquire a RendererAudioOutputStreamFactory and requests device
+ // authorization. On failure to aquire a factory, |callback| is destructed
+ // asynchronously.
+ void DoRequestDeviceAuthorization(const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ AuthorizationCB callback);
+
+ void ReceivedDeviceAuthorization(
+ base::TimeTicks auth_start_time,
+ media::mojom::blink::OutputDeviceStatus status,
+ const media::AudioParameters& params,
+ const String& device_id) const;
+
+ const FactoryAccessorCB factory_accessor_;
+
+ // This is the state that |delegate_| expects the stream to be in. It is
+ // maintained for when the stream is created.
+ enum { kPaused, kPlaying } expected_state_ = kPaused;
+ base::Optional<double> volume_;
+
+ mojo::Receiver<media::mojom::blink::AudioOutputStreamProviderClient>
+ receiver_{this};
+ mojo::Remote<media::mojom::blink::AudioOutputStreamProvider> stream_provider_;
+ mojo::Remote<media::mojom::blink::AudioOutputStream> stream_;
+ media::AudioOutputIPCDelegate* delegate_ = nullptr;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ // To make sure we don't send an "authorization completed" callback for a
+ // stream after it's closed, we use this weak factory.
+ base::WeakPtrFactory<MojoAudioOutputIPC> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputIPC);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_AUDIO_MOJO_AUDIO_OUTPUT_IPC_H_
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc_test.cc b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc_test.cc
new file mode 100644
index 00000000000..97e90787ce7
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc_test.cc
@@ -0,0 +1,636 @@
+// Copyright 2017 The Chromium Authors. 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/media/audio/mojo_audio_output_ipc.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/gtest_util.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_parameters.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/platform_handle.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/wtf/functional.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Invoke;
+using testing::Mock;
+using testing::StrictMock;
+
+namespace blink {
+
+namespace {
+
+const size_t kMemoryLength = 4321;
+const char kDeviceId[] = "device_id";
+const char kReturnedDeviceId[] = "returned_device_id";
+const double kNewVolume = 0.271828;
+
+media::AudioParameters Params() {
+ return media::AudioParameters::UnavailableDeviceParams();
+}
+
+MojoAudioOutputIPC::FactoryAccessorCB NullAccessor() {
+ return WTF::BindRepeating(
+ []() -> blink::mojom::blink::RendererAudioOutputStreamFactory* {
+ return nullptr;
+ });
+}
+
+// TODO(https://crbug.com/787252): Convert the test away from using std::string.
+class TestStreamProvider
+ : public media::mojom::blink::AudioOutputStreamProvider {
+ public:
+ explicit TestStreamProvider(media::mojom::blink::AudioOutputStream* stream)
+ : stream_(stream) {}
+
+ ~TestStreamProvider() override {
+ // If we expected a stream to be acquired, make sure it is so.
+ if (stream_)
+ EXPECT_TRUE(receiver_);
+ }
+
+ void Acquire(
+ const media::AudioParameters& params,
+ mojo::PendingRemote<media::mojom::blink::AudioOutputStreamProviderClient>
+ pending_provider_client) override {
+ EXPECT_EQ(receiver_, base::nullopt);
+ EXPECT_NE(stream_, nullptr);
+ provider_client_.reset();
+ provider_client_.Bind(std::move(pending_provider_client));
+ mojo::PendingRemote<media::mojom::blink::AudioOutputStream>
+ stream_pending_remote;
+ receiver_.emplace(stream_,
+ stream_pending_remote.InitWithNewPipeAndPassReceiver());
+ base::CancelableSyncSocket foreign_socket;
+ EXPECT_TRUE(
+ base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
+ provider_client_->Created(
+ std::move(stream_pending_remote),
+ {base::in_place, base::UnsafeSharedMemoryRegion::Create(kMemoryLength),
+ mojo::PlatformHandle(foreign_socket.Take())});
+ }
+
+ void SignalErrorToProviderClient() {
+ provider_client_.ResetWithReason(
+ static_cast<uint32_t>(media::mojom::blink::AudioOutputStreamObserver::
+ DisconnectReason::kPlatformError),
+ std::string());
+ }
+
+ private:
+ media::mojom::blink::AudioOutputStream* stream_;
+ mojo::Remote<media::mojom::blink::AudioOutputStreamProviderClient>
+ provider_client_;
+ base::Optional<mojo::Receiver<media::mojom::blink::AudioOutputStream>>
+ receiver_;
+ base::CancelableSyncSocket socket_;
+};
+
+class TestRemoteFactory
+ : public blink::mojom::blink::RendererAudioOutputStreamFactory {
+ public:
+ TestRemoteFactory()
+ : expect_request_(false),
+ receiver_(this, this_remote_.BindNewPipeAndPassReceiver()) {}
+
+ ~TestRemoteFactory() override {}
+
+ void RequestDeviceAuthorization(
+ mojo::PendingReceiver<media::mojom::blink::AudioOutputStreamProvider>
+ stream_provider_receiver,
+ const base::Optional<base::UnguessableToken>& session_id,
+ const String& device_id,
+ RequestDeviceAuthorizationCallback callback) override {
+ EXPECT_EQ(session_id, expected_session_id_);
+ EXPECT_EQ(device_id.Utf8(), expected_device_id_);
+ EXPECT_TRUE(expect_request_);
+ if (provider_) {
+ std::move(callback).Run(
+ static_cast<media::mojom::blink::OutputDeviceStatus>(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK),
+ Params(), String(kReturnedDeviceId));
+ provider_receiver_.emplace(provider_.get(),
+ std::move(stream_provider_receiver));
+ } else {
+ std::move(callback).Run(
+ static_cast<media::mojom::blink::OutputDeviceStatus>(
+ media::OutputDeviceStatus::
+ OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED),
+ Params(), String(""));
+ }
+ expect_request_ = false;
+ }
+
+ void PrepareProviderForAuthorization(
+ const base::UnguessableToken& session_id,
+ const std::string& device_id,
+ std::unique_ptr<TestStreamProvider> provider) {
+ EXPECT_FALSE(expect_request_);
+ expect_request_ = true;
+ expected_session_id_ = session_id.is_empty()
+ ? base::Optional<base::UnguessableToken>()
+ : session_id;
+ expected_device_id_ = device_id;
+ provider_receiver_.reset();
+ std::swap(provider_, provider);
+ }
+
+ void RefuseNextRequest(const base::UnguessableToken& session_id,
+ const std::string& device_id) {
+ EXPECT_FALSE(expect_request_);
+ expect_request_ = true;
+ expected_session_id_ = session_id;
+ expected_device_id_ = device_id;
+ }
+
+ void SignalErrorToProviderClient() {
+ provider_->SignalErrorToProviderClient();
+ }
+
+ void Disconnect() {
+ receiver_.reset();
+ this_remote_.reset();
+ receiver_.Bind(this_remote_.BindNewPipeAndPassReceiver());
+ provider_receiver_.reset();
+ provider_.reset();
+ expect_request_ = false;
+ }
+
+ MojoAudioOutputIPC::FactoryAccessorCB GetAccessor() {
+ return WTF::BindRepeating(&TestRemoteFactory::get, WTF::Unretained(this));
+ }
+
+ private:
+ blink::mojom::blink::RendererAudioOutputStreamFactory* get() {
+ return this_remote_.get();
+ }
+
+ bool expect_request_;
+ base::Optional<base::UnguessableToken> expected_session_id_;
+ std::string expected_device_id_;
+
+ mojo::Remote<blink::mojom::blink::RendererAudioOutputStreamFactory>
+ this_remote_;
+ mojo::Receiver<blink::mojom::blink::RendererAudioOutputStreamFactory>
+ receiver_{this};
+ std::unique_ptr<TestStreamProvider> provider_;
+ base::Optional<mojo::Receiver<media::mojom::blink::AudioOutputStreamProvider>>
+ provider_receiver_;
+};
+
+class MockStream : public media::mojom::blink::AudioOutputStream {
+ public:
+ MOCK_METHOD0(Play, void());
+ MOCK_METHOD0(Pause, void());
+ MOCK_METHOD0(Flush, void());
+ MOCK_METHOD1(SetVolume, void(double));
+};
+
+class MockDelegate : public media::AudioOutputIPCDelegate {
+ public:
+ MockDelegate() = default;
+ ~MockDelegate() override = default;
+
+ void OnStreamCreated(base::UnsafeSharedMemoryRegion mem_handle,
+ base::SyncSocket::ScopedHandle socket_handle,
+ bool playing_automatically) override {
+ GotOnStreamCreated();
+ }
+
+ MOCK_METHOD0(OnError, void());
+ MOCK_METHOD3(OnDeviceAuthorized,
+ void(media::OutputDeviceStatus device_status,
+ const media::AudioParameters& output_params,
+ const std::string& matched_device_id));
+ MOCK_METHOD0(GotOnStreamCreated, void());
+ MOCK_METHOD0(OnIPCClosed, void());
+};
+
+} // namespace
+
+TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsAuthorizedWithError) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ StrictMock<MockDelegate> delegate;
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ NullAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ // Don't call OnDeviceAuthorized synchronously, should wait until we run the
+ // RunLoop.
+ EXPECT_CALL(delegate,
+ OnDeviceAuthorized(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _,
+ std::string()));
+ base::RunLoop().RunUntilIdle();
+ ipc->CloseStream();
+}
+
+TEST(MojoAudioOutputIPC,
+ CreateWithoutAuthorizationWithoutFactory_CallsAuthorizedWithError) {
+ StrictMock<MockDelegate> delegate;
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ NullAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+
+ // No call to OnDeviceAuthorized since authotization wasn't explicitly
+ // requested.
+ base::RunLoop().RunUntilIdle();
+ ipc->CloseStream();
+}
+
+TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, OnDeviceCreated_Propagates) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+ CreateWithoutAuthorization_RequestsAuthorizationFirst) {
+ TestRemoteFactory stream_factory;
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ // Note: This call implicitly EXPECTs that authorization is requested,
+ // and constructing the TestStreamProvider with a |&stream| EXPECTs that the
+ // stream is created. This implicit request should always be for the default
+ // device and no session id.
+ stream_factory.PrepareProviderForAuthorization(
+ base::UnguessableToken(),
+ std::string(media::AudioDeviceDescription::kDefaultDeviceId),
+ std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, IsReusable) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ for (int i = 0; i < 5; ++i) {
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+
+ EXPECT_CALL(
+ delegate,
+ OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
+TEST(MojoAudioOutputIPC, IsReusableAfterError) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr));
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ stream_factory.Disconnect();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 0; i < 5; ++i) {
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+
+ EXPECT_CALL(
+ delegate,
+ OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ EXPECT_CALL(delegate, OnError());
+ stream_factory.SignalErrorToProviderClient();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&delegate);
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
+TEST(MojoAudioOutputIPC, DeviceNotAuthorized_Propagates) {
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockDelegate> delegate;
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.RefuseNextRequest(session_id, kDeviceId);
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ EXPECT_CALL(
+ delegate,
+ OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+ _, std::string()))
+ .WillOnce(Invoke([&](media::OutputDeviceStatus,
+ const media::AudioParameters&, const std::string&) {
+ ipc->CloseStream();
+ ipc.reset();
+ }));
+ EXPECT_CALL(delegate, OnError()).Times(AtLeast(0));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+ FactoryDisconnectedBeforeAuthorizationReply_CallsAuthorizedAnyways) {
+ // The authorization IPC message might be aborted by the remote end
+ // disconnecting. In this case, the MojoAudioOutputIPC object must still
+ // send a notification to unblock the AudioOutputIPCDelegate.
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ StrictMock<MockDelegate> delegate;
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ EXPECT_CALL(
+ delegate,
+ OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _,
+ std::string()))
+ .WillOnce(Invoke([&](media::OutputDeviceStatus,
+ const media::AudioParameters&, const std::string&) {
+ ipc->CloseStream();
+ ipc.reset();
+ }));
+ stream_factory.Disconnect();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+ FactoryDisconnectedAfterAuthorizationReply_CallsAuthorizedOnlyOnce) {
+ // This test makes sure that the MojoAudioOutputIPC doesn't callback for
+ // authorization when the factory disconnects if it already got a callback
+ // for authorization.
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ TestRemoteFactory stream_factory;
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr));
+ StrictMock<MockDelegate> delegate;
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ base::RunLoop().RunUntilIdle();
+
+ stream_factory.Disconnect();
+ base::RunLoop().RunUntilIdle();
+
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, AuthorizeNoClose_DCHECKs) {
+ TestRemoteFactory stream_factory;
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ StrictMock<MockDelegate> delegate;
+
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr));
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ EXPECT_DCHECK_DEATH(ipc.reset());
+ ipc->CloseStream();
+ ipc.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, CreateNoClose_DCHECKs) {
+ TestRemoteFactory stream_factory;
+ StrictMock<MockDelegate> delegate;
+ StrictMock<MockStream> stream;
+
+ stream_factory.PrepareProviderForAuthorization(
+ base::UnguessableToken(),
+ std::string(media::AudioDeviceDescription::kDefaultDeviceId),
+ std::make_unique<TestStreamProvider>(&stream));
+
+ std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+ EXPECT_DCHECK_DEATH(ipc.reset());
+ ipc->CloseStream();
+ ipc.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, Play_Plays) {
+ TestRemoteFactory stream_factory;
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ EXPECT_CALL(stream, Play());
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+ base::RunLoop().RunUntilIdle();
+ ipc->PlayStream();
+ base::RunLoop().RunUntilIdle();
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, Pause_Pauses) {
+ TestRemoteFactory stream_factory;
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ EXPECT_CALL(stream, Pause());
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+ base::RunLoop().RunUntilIdle();
+ ipc->PauseStream();
+ base::RunLoop().RunUntilIdle();
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, SetVolume_SetsVolume) {
+ TestRemoteFactory stream_factory;
+ const base::UnguessableToken session_id = base::UnguessableToken::Create();
+ StrictMock<MockStream> stream;
+ StrictMock<MockDelegate> delegate;
+
+ EXPECT_CALL(delegate, OnDeviceAuthorized(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+ _, std::string(kReturnedDeviceId)));
+ EXPECT_CALL(delegate, GotOnStreamCreated());
+ EXPECT_CALL(stream, SetVolume(kNewVolume));
+
+ const std::unique_ptr<media::AudioOutputIPC> ipc =
+ std::make_unique<MojoAudioOutputIPC>(
+ stream_factory.GetAccessor(),
+ blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+ stream_factory.PrepareProviderForAuthorization(
+ session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream));
+
+ ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId);
+ ipc->CreateStream(&delegate, Params(), base::nullopt);
+ base::RunLoop().RunUntilIdle();
+ ipc->SetVolume(kNewVolume);
+ base::RunLoop().RunUntilIdle();
+ ipc->CloseStream();
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/web_audio_device_factory.cc b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_device_factory.cc
new file mode 100644
index 00000000000..0d79ad45026
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_device_factory.cc
@@ -0,0 +1,235 @@
+// 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/web/modules/media/audio/web_audio_device_factory.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
+#include "base/notreached.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "media/audio/audio_input_device.h"
+#include "media/audio/audio_output_device.h"
+#include "media/base/audio_renderer_mixer_input.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/web/modules/media/audio/web_audio_input_ipc_factory.h"
+#include "third_party/blink/public/web/modules/media/audio/web_audio_output_ipc_factory.h"
+#include "third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_manager.h"
+#include "third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h"
+#include "third_party/blink/renderer/platform/wtf/wtf.h"
+
+namespace blink {
+
+// static
+WebAudioDeviceFactory* WebAudioDeviceFactory::factory_ = nullptr;
+
+namespace {
+
+#if defined(OS_WIN) || defined(OS_MAC) || \
+ (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+// Due to driver deadlock issues on Windows (http://crbug/422522) there is a
+// chance device authorization response is never received from the browser side.
+// In this case we will time out, to avoid renderer hang forever waiting for
+// device authorization (http://crbug/615589). This will result in "no audio".
+// There are also cases when authorization takes too long on Mac and Linux.
+constexpr base::TimeDelta kMaxAuthorizationTimeout =
+ base::TimeDelta::FromSeconds(10);
+#else
+constexpr base::TimeDelta kMaxAuthorizationTimeout; // No timeout.
+#endif
+
+base::TimeDelta GetDefaultAuthTimeout() {
+ // Set authorization request timeout at 80% of renderer hung timeout,
+ // but no more than kMaxAuthorizationTimeout.
+ return std::min(Platform::Current()->GetHungRendererDelay() * 8 / 10,
+ kMaxAuthorizationTimeout);
+}
+
+scoped_refptr<media::AudioOutputDevice> NewOutputDevice(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params,
+ base::TimeDelta auth_timeout) {
+ CHECK(blink::WebAudioOutputIPCFactory::GetInstance().io_task_runner());
+ auto device = base::MakeRefCounted<media::AudioOutputDevice>(
+ blink::WebAudioOutputIPCFactory::GetInstance().CreateAudioOutputIPC(
+ frame_token),
+ blink::WebAudioOutputIPCFactory::GetInstance().io_task_runner(), params,
+ auth_timeout);
+ device->RequestDeviceAuthorization();
+ return device;
+}
+
+// This is where we decide which audio will go to mixers and which one to
+// AudioOutputDevice directly.
+bool IsMixable(blink::WebAudioDeviceSourceType source_type) {
+ // Media element must ALWAYS go through mixer.
+ return source_type == blink::WebAudioDeviceSourceType::kMediaElement;
+}
+
+scoped_refptr<media::SwitchableAudioRendererSink> NewMixableSink(
+ blink::WebAudioDeviceSourceType source_type,
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ DCHECK(IsMainThread()) << __func__ << "() is called on a wrong thread.";
+ DCHECK(!params.processing_id.has_value());
+ return AudioRendererMixerManager::GetInstance().CreateInput(
+ frame_token, params.session_id, params.device_id,
+ WebAudioDeviceFactory::GetSourceLatencyType(source_type));
+}
+
+} // namespace
+
+media::AudioLatency::LatencyType WebAudioDeviceFactory::GetSourceLatencyType(
+ blink::WebAudioDeviceSourceType source) {
+ switch (source) {
+ case blink::WebAudioDeviceSourceType::kWebAudioInteractive:
+ return media::AudioLatency::LATENCY_INTERACTIVE;
+ case blink::WebAudioDeviceSourceType::kNone:
+ case blink::WebAudioDeviceSourceType::kWebRtc:
+ case blink::WebAudioDeviceSourceType::kNonRtcAudioTrack:
+ case blink::WebAudioDeviceSourceType::kWebAudioBalanced:
+ return media::AudioLatency::LATENCY_RTC;
+ case blink::WebAudioDeviceSourceType::kMediaElement:
+ case blink::WebAudioDeviceSourceType::kWebAudioPlayback:
+ return media::AudioLatency::LATENCY_PLAYBACK;
+ case blink::WebAudioDeviceSourceType::kWebAudioExact:
+ return media::AudioLatency::LATENCY_EXACT_MS;
+ }
+ NOTREACHED();
+ return media::AudioLatency::LATENCY_INTERACTIVE;
+}
+
+scoped_refptr<media::AudioRendererSink>
+WebAudioDeviceFactory::NewAudioRendererMixerSink(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ // AudioRendererMixer sinks are always used asynchronously and thus can
+ // operate without a timeout value.
+ return NewFinalAudioRendererSink(frame_token, params, base::TimeDelta());
+}
+
+// static
+scoped_refptr<media::AudioRendererSink>
+WebAudioDeviceFactory::NewAudioRendererSink(
+ blink::WebAudioDeviceSourceType source_type,
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ if (factory_) {
+ scoped_refptr<media::AudioRendererSink> device =
+ factory_->CreateAudioRendererSink(source_type, frame_token, params);
+ if (device)
+ return device;
+ }
+
+ // Perhaps streams with a processing ID just shouldn't be mixable, i.e. call
+ // NewFinalAudioRendererSink for them rather than DCHECK?
+ DCHECK(!(params.processing_id.has_value() && IsMixable(source_type)));
+
+ if (IsMixable(source_type))
+ return NewMixableSink(source_type, frame_token, params);
+
+ UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.SinkCache.UsedForSinkCreation",
+ false);
+ return NewFinalAudioRendererSink(frame_token, params,
+ GetDefaultAuthTimeout());
+}
+
+// static
+scoped_refptr<media::SwitchableAudioRendererSink>
+WebAudioDeviceFactory::NewSwitchableAudioRendererSink(
+ blink::WebAudioDeviceSourceType source_type,
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ if (factory_) {
+ scoped_refptr<media::SwitchableAudioRendererSink> sink =
+ factory_->CreateSwitchableAudioRendererSink(source_type, frame_token,
+ params);
+ if (sink)
+ return sink;
+ }
+
+ if (IsMixable(source_type))
+ return NewMixableSink(source_type, frame_token, params);
+
+ // AudioOutputDevice is not RestartableAudioRendererSink, so we can't return
+ // anything for those who wants to create an unmixable sink.
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+// static
+scoped_refptr<media::AudioCapturerSource>
+WebAudioDeviceFactory::NewAudioCapturerSource(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& params) {
+ if (factory_) {
+ // We don't pass on |session_id|, as this branch is only used for tests.
+ scoped_refptr<media::AudioCapturerSource> source =
+ factory_->CreateAudioCapturerSource(frame_token, params);
+ if (source)
+ return source;
+ }
+
+ return base::MakeRefCounted<media::AudioInputDevice>(
+ blink::WebAudioInputIPCFactory::GetInstance().CreateAudioInputIPC(
+ frame_token, params),
+ media::AudioInputDevice::Purpose::kUserInput,
+ media::AudioInputDevice::DeadStreamDetection::kEnabled);
+}
+
+// static
+media::OutputDeviceInfo WebAudioDeviceFactory::GetOutputDeviceInfo(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params) {
+ DCHECK(IsMainThread()) << __func__ << "() is called on a wrong thread.";
+ constexpr base::TimeDelta kDeleteTimeout =
+ base::TimeDelta::FromMilliseconds(5000);
+
+ // There's one process wide instance that lives on the render thread.
+ //
+ // TODO(crbug.com/787252): Replace the use of base::ThreadPool below by
+ // worker_pool::PostTask().
+ static base::NoDestructor<AudioRendererSinkCache> cache(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}),
+ base::BindRepeating(&WebAudioDeviceFactory::NewAudioRendererSink,
+ blink::WebAudioDeviceSourceType::kNone),
+ kDeleteTimeout);
+ return cache->GetSinkInfo(frame_token, params.session_id, params.device_id);
+}
+
+WebAudioDeviceFactory::WebAudioDeviceFactory() {
+ DCHECK(!factory_) << "Can't register two factories at once.";
+ factory_ = this;
+}
+
+WebAudioDeviceFactory::~WebAudioDeviceFactory() {
+ factory_ = nullptr;
+}
+
+// static
+scoped_refptr<media::AudioRendererSink>
+WebAudioDeviceFactory::NewFinalAudioRendererSink(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSinkParameters& params,
+ base::TimeDelta auth_timeout) {
+ if (factory_) {
+ scoped_refptr<media::AudioRendererSink> sink =
+ factory_->CreateFinalAudioRendererSink(frame_token, params,
+ auth_timeout);
+ if (sink)
+ return sink;
+ }
+
+ return NewOutputDevice(frame_token, params, auth_timeout);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/web_audio_input_ipc_factory.cc b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_input_ipc_factory.cc
new file mode 100644
index 00000000000..f3bd4282d94
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_input_ipc_factory.cc
@@ -0,0 +1,109 @@
+// Copyright 2017 The Chromium Authors. 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/modules/media/audio/web_audio_input_ipc_factory.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "media/audio/audio_source_parameters.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom-blink.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_local_frame_client.h"
+#include "third_party/blink/renderer/modules/media/audio/mojo_audio_input_ipc.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+namespace {
+
+void CreateMojoAudioInputStreamOnMainThread(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& source_params,
+ mojo::PendingRemote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ client,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments) {
+ if (auto* web_frame = static_cast<WebLocalFrame*>(
+ blink::WebFrame::FromFrameToken(frame_token))) {
+ web_frame->Client()->CreateAudioInputStream(
+ std::move(client), source_params.session_id, params,
+ automatic_gain_control, total_segments);
+ }
+}
+
+void CreateMojoAudioInputStream(
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& source_params,
+ mojo::PendingRemote<mojom::blink::RendererAudioInputStreamFactoryClient>
+ client,
+ const media::AudioParameters& params,
+ bool automatic_gain_control,
+ uint32_t total_segments) {
+ main_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CreateMojoAudioInputStreamOnMainThread, frame_token,
+ source_params, std::move(client), params,
+ automatic_gain_control, total_segments));
+}
+
+void AssociateInputAndOutputForAec(
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+ const blink::LocalFrameToken& frame_token,
+ const base::UnguessableToken& input_stream_id,
+ const std::string& output_device_id) {
+ auto task = base::BindOnce(
+ [](const blink::LocalFrameToken& frame_token,
+ const base::UnguessableToken& input_stream_id,
+ const std::string& output_device_id) {
+ if (auto* web_frame = static_cast<WebLocalFrame*>(
+ WebFrame::FromFrameToken(frame_token))) {
+ web_frame->Client()->AssociateInputAndOutputForAec(input_stream_id,
+ output_device_id);
+ }
+ },
+ frame_token, input_stream_id, output_device_id);
+ main_task_runner->PostTask(FROM_HERE, std::move(task));
+}
+} // namespace
+
+WebAudioInputIPCFactory& WebAudioInputIPCFactory::GetInstance() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(WebAudioInputIPCFactory, instance,
+ (Thread::MainThread()->GetTaskRunner(),
+ Platform::Current()->GetIOTaskRunner()));
+ return instance;
+}
+
+WebAudioInputIPCFactory::WebAudioInputIPCFactory(
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : main_task_runner_(std::move(main_task_runner)),
+ io_task_runner_(std::move(io_task_runner)) {}
+
+WebAudioInputIPCFactory::~WebAudioInputIPCFactory() = default;
+
+std::unique_ptr<media::AudioInputIPC>
+WebAudioInputIPCFactory::CreateAudioInputIPC(
+ const blink::LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& source_params) const {
+ CHECK(!source_params.session_id.is_empty());
+ return std::make_unique<MojoAudioInputIPC>(
+ source_params,
+ base::BindRepeating(&CreateMojoAudioInputStream, main_task_runner_,
+ frame_token),
+ base::BindRepeating(&AssociateInputAndOutputForAec, main_task_runner_,
+ frame_token));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory.cc b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory.cc
new file mode 100644
index 00000000000..97b4c7298ca
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory.cc
@@ -0,0 +1,149 @@
+// Copyright 2017 The Chromium Authors. 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/modules/media/audio/web_audio_output_ipc_factory.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom-blink.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+
+namespace blink {
+
+class WebAudioOutputIPCFactory::Impl {
+ public:
+ using StreamFactoryMap = WTF::HashMap<
+ uint64_t,
+ mojo::Remote<mojom::blink::RendererAudioOutputStreamFactory>>;
+
+ explicit Impl(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : io_task_runner_(std::move(io_task_runner)) {}
+ ~Impl() { DCHECK(factory_remotes_.IsEmpty()); }
+
+ mojom::blink::RendererAudioOutputStreamFactory* GetRemoteFactory(
+ const blink::LocalFrameToken& frame_token) const;
+
+ void RegisterRemoteFactoryOnIOThread(
+ const blink::LocalFrameToken& frame_token,
+ mojo::PendingRemote<mojom::blink::RendererAudioOutputStreamFactory>
+ factory_pending_remote);
+
+ void MaybeDeregisterRemoteFactoryOnIOThread(
+ const blink::LocalFrameToken& frame_token);
+
+ // Maps frame id to the corresponding factory.
+ StreamFactoryMap factory_remotes_;
+ const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Impl);
+};
+
+// static
+WebAudioOutputIPCFactory& WebAudioOutputIPCFactory::GetInstance() {
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(WebAudioOutputIPCFactory, instance,
+ (Platform::Current()->GetIOTaskRunner()));
+ return instance;
+}
+
+WebAudioOutputIPCFactory::WebAudioOutputIPCFactory(
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : impl_(std::make_unique<Impl>(std::move(io_task_runner))) {}
+
+WebAudioOutputIPCFactory::~WebAudioOutputIPCFactory() = default;
+
+std::unique_ptr<media::AudioOutputIPC>
+WebAudioOutputIPCFactory::CreateAudioOutputIPC(
+ const blink::LocalFrameToken& frame_token) const {
+ // Unretained is safe due to the contract at the top of the header file.
+ return std::make_unique<MojoAudioOutputIPC>(
+ base::BindRepeating(&WebAudioOutputIPCFactory::Impl::GetRemoteFactory,
+ base::Unretained(impl_.get()), frame_token),
+ io_task_runner());
+}
+
+void WebAudioOutputIPCFactory::RegisterRemoteFactory(
+ const blink::LocalFrameToken& frame_token,
+ blink::BrowserInterfaceBrokerProxy* interface_broker) {
+ mojo::PendingRemote<mojom::blink::RendererAudioOutputStreamFactory>
+ factory_remote;
+ interface_broker->GetInterface(
+ factory_remote.InitWithNewPipeAndPassReceiver());
+ // Unretained is safe due to the contract at the top of the header file.
+ // It's safe to pass the |factory_remote| PendingRemote between threads.
+ io_task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WebAudioOutputIPCFactory::Impl::RegisterRemoteFactoryOnIOThread,
+ base::Unretained(impl_.get()), frame_token,
+ std::move(factory_remote)));
+}
+
+void WebAudioOutputIPCFactory::MaybeDeregisterRemoteFactory(
+ const blink::LocalFrameToken& frame_token) {
+ io_task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&WebAudioOutputIPCFactory::Impl::
+ MaybeDeregisterRemoteFactoryOnIOThread,
+ base::Unretained(impl_.get()), frame_token));
+}
+
+const scoped_refptr<base::SingleThreadTaskRunner>&
+WebAudioOutputIPCFactory::io_task_runner() const {
+ return impl_->io_task_runner_;
+}
+
+mojom::blink::RendererAudioOutputStreamFactory*
+WebAudioOutputIPCFactory::Impl::GetRemoteFactory(
+ const blink::LocalFrameToken& frame_token) const {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ auto it = factory_remotes_.find(LocalFrameToken::Hasher()(frame_token));
+ return it == factory_remotes_.end() ? nullptr : it->value.get();
+}
+
+void WebAudioOutputIPCFactory::Impl::RegisterRemoteFactoryOnIOThread(
+ const blink::LocalFrameToken& frame_token,
+ mojo::PendingRemote<mojom::blink::RendererAudioOutputStreamFactory>
+ factory_pending_remote) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ mojo::Remote<mojom::blink::RendererAudioOutputStreamFactory> factory_remote(
+ std::move(factory_pending_remote));
+
+ auto emplace_result = factory_remotes_.insert(
+ LocalFrameToken::Hasher()(frame_token), std::move(factory_remote));
+
+ DCHECK(emplace_result.is_new_entry) << "Attempt to register a factory for a "
+ "frame which already has a factory "
+ "registered.";
+
+ auto& emplaced_factory = emplace_result.stored_value->value;
+ DCHECK(emplaced_factory.is_bound())
+ << "Factory is not bound to a remote implementation.";
+
+ // Unretained is safe because |this| owns the remote, so a connection error
+ // cannot trigger after destruction.
+ emplaced_factory.set_disconnect_handler(base::BindOnce(
+ &WebAudioOutputIPCFactory::Impl::MaybeDeregisterRemoteFactoryOnIOThread,
+ base::Unretained(this), frame_token));
+}
+
+void WebAudioOutputIPCFactory::Impl::MaybeDeregisterRemoteFactoryOnIOThread(
+ const blink::LocalFrameToken& frame_token) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ // This function can be called both by the frame and the connection error
+ // handler of the factory remote. Calling erase multiple times even though
+ // there is nothing to erase is safe, so we don't have to handle this in any
+ // particular way.
+ factory_remotes_.erase(LocalFrameToken::Hasher()(frame_token));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory_test.cc b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory_test.cc
new file mode 100644
index 00000000000..9d11aca74fa
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media/audio/web_audio_output_ipc_factory_test.cc
@@ -0,0 +1,254 @@
+// Copyright 2017 The Chromium Authors. 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/modules/media/audio/web_audio_output_ipc_factory.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/threading/thread.h"
+#include "media/audio/audio_output_ipc.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom-blink.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+
+using ::testing::_;
+
+namespace blink {
+
+namespace {
+
+const int kRenderFrameId = 0;
+
+blink::LocalFrameToken TokenFromInt(int i) {
+ static base::UnguessableToken base_token = base::UnguessableToken::Create();
+ return blink::LocalFrameToken(base::UnguessableToken::Deserialize(
+ base_token.GetHighForSerialization() + i,
+ base_token.GetLowForSerialization() + i));
+}
+
+std::unique_ptr<base::Thread> MakeIOThread() {
+ auto io_thread = std::make_unique<base::Thread>("test IO thread");
+ base::Thread::Options thread_options(base::MessagePumpType::IO, 0);
+ CHECK(io_thread->StartWithOptions(thread_options));
+ return io_thread;
+}
+
+class FakeRemoteFactory
+ : public mojom::blink::RendererAudioOutputStreamFactory {
+ public:
+ FakeRemoteFactory() = default;
+ ~FakeRemoteFactory() override {}
+
+ void RequestDeviceAuthorization(
+ mojo::PendingReceiver<media::mojom::blink::AudioOutputStreamProvider>
+ stream_provider,
+ const base::Optional<base::UnguessableToken>& session_id,
+ const String& device_id,
+ RequestDeviceAuthorizationCallback callback) override {
+ std::move(callback).Run(
+ static_cast<media::mojom::blink::OutputDeviceStatus>(
+ media::OutputDeviceStatus::
+ OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED),
+ media::AudioParameters::UnavailableDeviceParams(), WTF::g_empty_string);
+ EXPECT_FALSE(on_called_.is_null());
+ std::move(on_called_).Run();
+ }
+
+ void SetOnCalledCallback(base::OnceClosure on_called) {
+ on_called_ = std::move(on_called);
+ }
+
+ void Bind(mojo::ScopedMessagePipeHandle handle) {
+ EXPECT_FALSE(receiver_.is_bound());
+ receiver_.Bind(
+ mojo::PendingReceiver<mojom::blink::RendererAudioOutputStreamFactory>(
+ std::move(handle)));
+ }
+
+ private:
+ mojo::Receiver<mojom::blink::RendererAudioOutputStreamFactory> receiver_{
+ this};
+ base::OnceClosure on_called_;
+};
+
+class FakeAudioOutputIPCDelegate : public media::AudioOutputIPCDelegate {
+ void OnError() override {}
+ void OnDeviceAuthorized(media::OutputDeviceStatus device_status,
+ const media::AudioParameters& output_params,
+ const std::string& matched_device_id) override {}
+ void OnStreamCreated(base::UnsafeSharedMemoryRegion region,
+ base::SyncSocket::ScopedHandle socket_handle,
+ bool playing_automatically) override {}
+ void OnIPCClosed() override {}
+};
+
+} // namespace
+
+class WebAudioOutputIPCFactoryTest : public testing::Test {
+ public:
+ WebAudioOutputIPCFactoryTest() = default;
+ ~WebAudioOutputIPCFactoryTest() override = default;
+
+ void RequestAuthorizationOnIOThread(
+ std::unique_ptr<media::AudioOutputIPC> output_ipc) {
+ output_ipc->RequestDeviceAuthorization(&fake_delegate,
+ base::UnguessableToken(), "");
+
+ output_ipc->CloseStream();
+ }
+
+ private:
+ FakeAudioOutputIPCDelegate fake_delegate;
+};
+
+TEST_F(WebAudioOutputIPCFactoryTest, CallFactoryFromIOThread) {
+ // This test makes sure that WebAudioOutputIPCFactory correctly binds the
+ // RendererAudioOutputStreamFactory to the IO thread.
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
+ base::RunLoop run_loop;
+ auto io_thread = MakeIOThread();
+
+ FakeRemoteFactory remote_factory;
+ remote_factory.SetOnCalledCallback(run_loop.QuitWhenIdleClosure());
+
+ auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_,
+ base::BindRepeating(&FakeRemoteFactory::Bind,
+ base::Unretained(&remote_factory)));
+
+ WebAudioOutputIPCFactory ipc_factory(io_thread->task_runner());
+
+ ipc_factory.RegisterRemoteFactory(TokenFromInt(kRenderFrameId),
+ &interface_broker);
+
+ // To make sure that the pointer stored in |ipc_factory| is connected to
+ // |remote_factory|, and also that it's bound to |io_thread|, we create an
+ // AudioOutputIPC object and request device authorization on the IO thread.
+ // This is supposed to call |remote_factory| on the main thread.
+ io_thread->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WebAudioOutputIPCFactoryTest::RequestAuthorizationOnIOThread,
+ base::Unretained(this),
+ ipc_factory.CreateAudioOutputIPC(TokenFromInt(kRenderFrameId))));
+
+ // Wait for call to |remote_factory|:
+ run_loop.Run();
+
+ ipc_factory.MaybeDeregisterRemoteFactory(TokenFromInt(0));
+
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_, {});
+
+ io_thread.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(WebAudioOutputIPCFactoryTest, SeveralFactories) {
+ // This test simulates having several frames being created and destructed.
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
+ auto io_thread = MakeIOThread();
+ const int n_factories = 5;
+
+ std::vector<FakeRemoteFactory> remote_factories(n_factories);
+
+ auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
+
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_,
+ base::BindLambdaForTesting([&](mojo::ScopedMessagePipeHandle handle) {
+ static int factory_index = 0;
+ DCHECK_LT(factory_index, n_factories);
+ remote_factories[factory_index++].Bind(std::move(handle));
+ }));
+
+ base::RunLoop().RunUntilIdle();
+
+ WebAudioOutputIPCFactory ipc_factory(io_thread->task_runner());
+
+ for (size_t i = 0; i < n_factories; i++) {
+ ipc_factory.RegisterRemoteFactory(TokenFromInt(kRenderFrameId + i),
+ &interface_broker);
+ }
+
+ base::RunLoop run_loop;
+ remote_factories[0].SetOnCalledCallback(run_loop.QuitWhenIdleClosure());
+ io_thread->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WebAudioOutputIPCFactoryTest::RequestAuthorizationOnIOThread,
+ base::Unretained(this),
+ ipc_factory.CreateAudioOutputIPC(TokenFromInt(kRenderFrameId))));
+ run_loop.Run();
+
+ // Do some operation and make sure the internal state isn't messed up:
+ ipc_factory.MaybeDeregisterRemoteFactory(TokenFromInt(1));
+
+ base::RunLoop run_loop2;
+ remote_factories[2].SetOnCalledCallback(run_loop2.QuitWhenIdleClosure());
+ io_thread->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WebAudioOutputIPCFactoryTest::RequestAuthorizationOnIOThread,
+ base::Unretained(this),
+ ipc_factory.CreateAudioOutputIPC(TokenFromInt(kRenderFrameId + 2))));
+ run_loop2.Run();
+
+ for (size_t i = 0; i < n_factories; i++) {
+ if (i == 1)
+ continue;
+ ipc_factory.MaybeDeregisterRemoteFactory(TokenFromInt(i));
+ }
+
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_, {});
+
+ io_thread.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(WebAudioOutputIPCFactoryTest, RegisterDeregisterBackToBack_Deregisters) {
+ // This test makes sure that calling Register... followed by Deregister...
+ // correctly sequences the registration before the deregistration.
+ ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
+
+ auto io_thread = MakeIOThread();
+
+ FakeRemoteFactory remote_factory;
+
+ auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_,
+ base::BindRepeating(&FakeRemoteFactory::Bind,
+ base::Unretained(&remote_factory)));
+
+ WebAudioOutputIPCFactory ipc_factory(io_thread->task_runner());
+
+ ipc_factory.RegisterRemoteFactory(TokenFromInt(kRenderFrameId),
+ &interface_broker);
+ ipc_factory.MaybeDeregisterRemoteFactory(TokenFromInt(kRenderFrameId));
+ // That there is no factory remaining at destruction is DCHECKed in the
+ // WebAudioOutputIPCFactory destructor.
+
+ base::RunLoop().RunUntilIdle();
+
+ interface_broker.SetBinderForTesting(
+ mojom::blink::RendererAudioOutputStreamFactory::Name_, {});
+ io_thread.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn b/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
index e2f52506dc6..958d37191eb 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
@@ -10,6 +10,8 @@ blink_modules_sources("media_capabilities") {
sources = [
"media_capabilities.cc",
"media_capabilities.h",
+ "media_capabilities_identifiability_metrics.cc",
+ "media_capabilities_identifiability_metrics.h",
"navigator_media_capabilities.cc",
"navigator_media_capabilities.h",
"worker_navigator_media_capabilities.cc",
@@ -18,6 +20,7 @@ blink_modules_sources("media_capabilities") {
deps = [
"//media",
"//media/learning/mojo:impl",
+ "//third_party/blink/renderer/modules/encryptedmedia:encryptedmedia",
"//third_party/blink/renderer/modules/mediarecorder",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
index c254ff713ea..9b833e9c636 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
@@ -53,6 +53,7 @@
#include "third_party/blink/renderer/modules/encryptedmedia/media_key_system_access.h"
#include "third_party/blink/renderer/modules/encryptedmedia/media_key_system_access_initializer_base.h"
#include "third_party/blink/renderer/modules/encryptedmedia/media_keys_controller.h"
+#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.h"
#include "third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -141,6 +142,16 @@ MediaCapabilitiesDecodingInfo* CreateDecodingInfoWith(bool value) {
return info;
}
+ScriptPromise CreateResolvedPromiseToDecodingInfoWith(
+ bool value,
+ ScriptState* script_state,
+ const MediaDecodingConfiguration* config) {
+ MediaCapabilitiesDecodingInfo* info = CreateDecodingInfoWith(value);
+ media_capabilities_identifiability_metrics::ReportDecodingInfoResult(
+ ExecutionContext::From(script_state), config, info);
+ return ScriptPromise::Cast(script_state, ToV8(info, script_state));
+}
+
MediaCapabilitiesDecodingInfo* CreateEncryptedDecodingInfoWith(
bool value,
MediaKeySystemAccess* access) {
@@ -398,7 +409,7 @@ bool CheckMseSupport(const String& mime_type, const String& codec) {
void ParseDynamicRangeConfigurations(
const blink::VideoConfiguration* video_config,
media::VideoColorSpace* color_space,
- media::HdrMetadataType* hdr_metadata) {
+ gl::HdrMetadataType* hdr_metadata) {
DCHECK(color_space);
DCHECK(hdr_metadata);
@@ -410,16 +421,16 @@ void ParseDynamicRangeConfigurations(
const auto& hdr_metadata_type = video_config->hdrMetadataType();
// TODO(crbug.com/1092328): Switch by V8HdrMetadataType::Enum.
if (hdr_metadata_type == kSmpteSt2086HdrMetadataType) {
- *hdr_metadata = media::HdrMetadataType::kSmpteSt2086;
+ *hdr_metadata = gl::HdrMetadataType::kSmpteSt2086;
} else if (hdr_metadata_type == kSmpteSt209410HdrMetadataType) {
- *hdr_metadata = media::HdrMetadataType::kSmpteSt2094_10;
+ *hdr_metadata = gl::HdrMetadataType::kSmpteSt2094_10;
} else if (hdr_metadata_type == kSmpteSt209440HdrMetadataType) {
- *hdr_metadata = media::HdrMetadataType::kSmpteSt2094_40;
+ *hdr_metadata = gl::HdrMetadataType::kSmpteSt2094_40;
} else {
NOTREACHED();
}
} else {
- *hdr_metadata = media::HdrMetadataType::kNone;
+ *hdr_metadata = gl::HdrMetadataType::kNone;
}
if (video_config->hasColorGamut()) {
@@ -544,7 +555,7 @@ bool IsAudioConfigurationSupported(
bool IsVideoConfigurationSupported(const String& mime_type,
const String& codec,
media::VideoColorSpace video_color_space,
- media::HdrMetadataType hdr_metadata_type) {
+ gl::HdrMetadataType hdr_metadata_type) {
media::VideoCodec video_codec = media::kUnknownVideoCodec;
media::VideoCodecProfile video_profile;
uint8_t video_level = 0;
@@ -618,10 +629,12 @@ void MediaCapabilities::Trace(blink::Visitor* visitor) const {
MediaCapabilities::PendingCallbackState::PendingCallbackState(
ScriptPromiseResolver* resolver,
MediaKeySystemAccess* access,
- const base::TimeTicks& request_time)
+ const base::TimeTicks& request_time,
+ base::Optional<IdentifiableToken> input_token)
: resolver(resolver),
key_system_access(access),
- request_time(request_time) {}
+ request_time(request_time),
+ input_token(input_token) {}
void MediaCapabilities::PendingCallbackState::Trace(
blink::Visitor* visitor) const {
@@ -690,9 +703,11 @@ ScriptPromise MediaCapabilities::decodingInfo(
!CheckMseSupport(video_mime_str, video_codec_str))) {
// Unsupported EME queries should resolve with a null
// MediaKeySystemAccess.
- return ScriptPromise::Cast(
- script_state,
- ToV8(CreateEncryptedDecodingInfoWith(false, nullptr), script_state));
+ MediaCapabilitiesDecodingInfo* info =
+ CreateEncryptedDecodingInfoWith(false, nullptr);
+ media_capabilities_identifiability_metrics::ReportDecodingInfoResult(
+ ExecutionContext::From(script_state), config, info);
+ return ScriptPromise::Cast(script_state, ToV8(info, script_state));
}
}
@@ -712,15 +727,14 @@ ScriptPromise MediaCapabilities::decodingInfo(
message);
}
- return ScriptPromise::Cast(
- script_state, ToV8(CreateDecodingInfoWith(false), script_state));
+ return CreateResolvedPromiseToDecodingInfoWith(false, script_state, config);
}
// Validation errors should return above.
DCHECK(message.IsEmpty());
media::VideoColorSpace video_color_space;
- media::HdrMetadataType hdr_metadata_type = media::HdrMetadataType::kNone;
+ gl::HdrMetadataType hdr_metadata_type = gl::HdrMetadataType::kNone;
if (config->hasVideo()) {
ParseDynamicRangeConfigurations(config->video(), &video_color_space,
&hdr_metadata_type);
@@ -744,9 +758,8 @@ ScriptPromise MediaCapabilities::decodingInfo(
// No need to check video capabilities if video not included in configuration
// or when audio is already known to be unsupported.
if (!audio_supported || !config->hasVideo()) {
- return ScriptPromise::Cast(
- script_state,
- ToV8(CreateDecodingInfoWith(audio_supported), script_state));
+ return CreateResolvedPromiseToDecodingInfoWith(audio_supported,
+ script_state, config);
}
DCHECK(message.IsEmpty());
@@ -755,8 +768,7 @@ ScriptPromise MediaCapabilities::decodingInfo(
// Return early for unsupported configurations.
if (!IsVideoConfigurationSupported(video_mime_str, video_codec_str,
video_color_space, hdr_metadata_type)) {
- return ScriptPromise::Cast(
- script_state, ToV8(CreateDecodingInfoWith(false), script_state));
+ return CreateResolvedPromiseToDecodingInfoWith(false, script_state, config);
}
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -1059,6 +1071,8 @@ void MediaCapabilities::GetPerfInfo(
// Audio-only is always smooth and power efficient.
MediaCapabilitiesDecodingInfo* info = CreateDecodingInfoWith(true);
info->setKeySystemAccess(access);
+ media_capabilities_identifiability_metrics::ReportDecodingInfoResult(
+ execution_context, decoding_config, info);
resolver->Resolve(info);
return;
}
@@ -1073,7 +1087,10 @@ void MediaCapabilities::GetPerfInfo(
}
if (!EnsurePerfHistoryService(execution_context)) {
- resolver->Resolve(WrapPersistent(CreateDecodingInfoWith(true)));
+ MediaCapabilitiesDecodingInfo* info = CreateDecodingInfoWith(true);
+ media_capabilities_identifiability_metrics::ReportDecodingInfoResult(
+ execution_context, decoding_config, info);
+ resolver->Resolve(WrapPersistent(info));
return;
}
@@ -1081,7 +1098,9 @@ void MediaCapabilities::GetPerfInfo(
pending_cb_map_.insert(
callback_id,
MakeGarbageCollected<MediaCapabilities::PendingCallbackState>(
- resolver, access, request_time));
+ resolver, access, request_time,
+ media_capabilities_identifiability_metrics::
+ ComputeDecodingInfoInputToken(decoding_config)));
if (base::FeatureList::IsEnabled(media::kMediaLearningSmoothnessExperiment)) {
GetPerfInfo_ML(execution_context, callback_id, video_codec, video_profile,
@@ -1296,6 +1315,8 @@ void MediaCapabilities::ResolveCallbackIfReady(int callback_id) {
process_time);
}
+ media_capabilities_identifiability_metrics::ReportDecodingInfoResult(
+ execution_context, pending_cb->input_token, info);
pending_cb->resolver->Resolve(std::move(info));
pending_cb_map_.erase(callback_id);
}
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h
index a72e3f58ea3..7ed2617a749 100644
--- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.h
@@ -9,6 +9,7 @@
#include "media/learning/mojo/public/cpp/mojo_learning_task_controller.h"
#include "media/learning/mojo/public/mojom/learning_task_controller.mojom-blink.h"
#include "media/mojo/mojom/video_decode_perf_history.mojom-blink.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_configuration.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -51,7 +52,8 @@ class MODULES_EXPORT MediaCapabilities final : public ScriptWrappable {
public:
PendingCallbackState(ScriptPromiseResolver* resolver,
MediaKeySystemAccess* access,
- const base::TimeTicks& request_time);
+ const base::TimeTicks& request_time,
+ base::Optional<IdentifiableToken> input_token);
virtual void Trace(blink::Visitor* visitor) const;
Member<ScriptPromiseResolver> resolver;
@@ -62,6 +64,7 @@ class MODULES_EXPORT MediaCapabilities final : public ScriptWrappable {
base::Optional<bool> db_is_power_efficient;
base::Optional<bool> is_gpu_factories_supported;
base::TimeTicks request_time;
+ base::Optional<IdentifiableToken> input_token;
};
// Lazily binds remote LearningTaskControllers for ML smoothness predictions
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
new file mode 100644
index 00000000000..ff7af6102ad
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
@@ -0,0 +1,261 @@
+// Copyright 2020 The Chromium Authors. 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/media_capabilities/media_capabilities_identifiability_metrics.h"
+
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_key_system_track_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_capabilities_decoding_info.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_capabilities_key_system_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_decoding_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_key_system_access.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_key_system_configuration.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_key_system_media_capability.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_configuration.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
+
+namespace blink {
+namespace media_capabilities_identifiability_metrics {
+namespace {
+
+bool IsDecodingInfoTypeAllowed() {
+ return IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+ IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
+}
+
+bool ShouldSampleDecodingInfoType() {
+ return IdentifiabilityStudySettings::Get()->ShouldSample(
+ IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
+}
+
+void RecordDecodingIdentifiabilityMetric(ExecutionContext* context,
+ IdentifiableToken input_token,
+ IdentifiableToken output_token) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ IdentifiabilityMetricBuilder(context->UkmSourceID())
+ .Set(IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo,
+ input_token),
+ output_token)
+ .Record(context->UkmRecorder());
+}
+
+// The various ComputeToken methods create digests of each of the objects,
+// returning the special empty value when an input is nullptr.
+IdentifiableToken ComputeToken(const VideoConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder
+ .AddToken(IdentifiabilityBenignStringToken(configuration->contentType()))
+ .AddToken(
+ IdentifiabilityBenignStringToken(configuration->hdrMetadataType()))
+ .AddToken(IdentifiabilityBenignStringToken(configuration->colorGamut()))
+ .AddToken(
+ IdentifiabilityBenignStringToken(configuration->transferFunction()));
+
+ // While the strings above will be null if not present, we need to check
+ // the presence of numerical types explicitly.
+ builder.AddValue(configuration->hasWidth())
+ .AddValue(configuration->hasHeight())
+ .AddValue(configuration->hasBitrate())
+ .AddValue(configuration->hasFramerate());
+ if (configuration->hasWidth())
+ builder.AddValue(configuration->width());
+ if (configuration->hasHeight())
+ builder.AddValue(configuration->height());
+ if (configuration->hasBitrate())
+ builder.AddValue(configuration->bitrate());
+ if (configuration->hasFramerate())
+ builder.AddValue(configuration->framerate());
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(const AudioConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder
+ .AddToken(IdentifiabilityBenignStringToken(configuration->contentType()))
+ .AddToken(IdentifiabilityBenignStringToken(configuration->channels()));
+
+ // While the strings above will be null if not present, we need to check
+ // the presence of numerical types explicitly.
+ builder.AddValue(configuration->hasBitrate())
+ .AddValue(configuration->hasSamplerate());
+ if (configuration->hasBitrate())
+ builder.AddValue(configuration->bitrate());
+ if (configuration->hasSamplerate())
+ builder.AddValue(configuration->samplerate());
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(
+ const KeySystemTrackConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(
+ IdentifiabilityBenignStringToken(configuration->robustness()));
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(
+ const MediaKeySystemMediaCapability* capability) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!capability)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(IdentifiabilityBenignStringToken(capability->contentType()))
+ .AddToken(IdentifiabilityBenignStringToken(capability->robustness()))
+ .AddToken(
+ IdentifiabilityBenignStringToken(capability->encryptionScheme()));
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(
+ const MediaKeySystemConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(IdentifiabilityBenignStringToken(configuration->label()))
+ .AddValue(configuration->hasInitDataTypes())
+ .AddValue(configuration->hasAudioCapabilities())
+ .AddValue(configuration->hasVideoCapabilities())
+ .AddToken(IdentifiabilityBenignStringToken(
+ configuration->distinctiveIdentifier()))
+ .AddToken(
+ IdentifiabilityBenignStringToken(configuration->persistentState()))
+ .AddValue(configuration->hasSessionTypes());
+ if (configuration->hasInitDataTypes()) {
+ builder.AddToken(
+ IdentifiabilityBenignStringVectorToken(configuration->initDataTypes()));
+ }
+ if (configuration->hasAudioCapabilities()) {
+ const HeapVector<Member<MediaKeySystemMediaCapability>>&
+ audio_capabilities = configuration->audioCapabilities();
+ builder.AddValue(audio_capabilities.size());
+ for (const auto& elem : audio_capabilities)
+ builder.AddToken(ComputeToken(elem.Get()));
+ }
+ if (configuration->hasVideoCapabilities()) {
+ const HeapVector<Member<MediaKeySystemMediaCapability>>&
+ video_capabilities = configuration->videoCapabilities();
+ builder.AddValue(video_capabilities.size());
+ for (const auto& elem : video_capabilities)
+ builder.AddToken(ComputeToken(elem.Get()));
+ }
+ if (configuration->hasSessionTypes()) {
+ builder.AddToken(
+ IdentifiabilityBenignStringVectorToken(configuration->sessionTypes()));
+ }
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(const MediaKeySystemAccess* access) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!access)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(IdentifiabilityBenignStringToken(access->keySystem()))
+ .AddToken(ComputeToken(access->getConfiguration()));
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(
+ const MediaCapabilitiesKeySystemConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(IdentifiabilityBenignStringToken(configuration->keySystem()))
+ .AddToken(IdentifiabilityBenignStringToken(configuration->initDataType()))
+ .AddToken(IdentifiabilityBenignStringToken(
+ configuration->distinctiveIdentifier()))
+ .AddValue(configuration->hasSessionTypes())
+ .AddToken(ComputeToken(configuration->audio()))
+ .AddToken(ComputeToken(configuration->video()));
+ if (configuration->hasSessionTypes()) {
+ builder.AddToken(
+ IdentifiabilityBenignStringVectorToken(configuration->sessionTypes()));
+ }
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(
+ const MediaDecodingConfiguration* configuration) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!configuration)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddToken(IdentifiabilityBenignStringToken(configuration->type()))
+ .AddToken(ComputeToken(configuration->keySystemConfiguration()))
+ .AddToken(ComputeToken(configuration->video()))
+ .AddToken(ComputeToken(configuration->audio()));
+ return builder.GetToken();
+}
+
+IdentifiableToken ComputeToken(const MediaCapabilitiesDecodingInfo* info) {
+ DCHECK(IsDecodingInfoTypeAllowed());
+ if (!info)
+ return IdentifiableToken();
+
+ IdentifiableTokenBuilder builder;
+ builder.AddValue(info->supported())
+ .AddValue(info->smooth())
+ .AddValue(info->powerEfficient())
+ .AddToken(ComputeToken(info->keySystemAccess()));
+ return builder.GetToken();
+}
+
+} // namespace
+
+void ReportDecodingInfoResult(ExecutionContext* context,
+ const MediaDecodingConfiguration* input,
+ const MediaCapabilitiesDecodingInfo* output) {
+ if (!IsDecodingInfoTypeAllowed() || !ShouldSampleDecodingInfoType())
+ return;
+
+ RecordDecodingIdentifiabilityMetric(context, ComputeToken(input),
+ ComputeToken(output));
+}
+
+void ReportDecodingInfoResult(ExecutionContext* context,
+ base::Optional<IdentifiableToken> input_token,
+ const MediaCapabilitiesDecodingInfo* output) {
+ DCHECK_EQ(IsDecodingInfoTypeAllowed(), input_token.has_value());
+ if (!input_token.has_value() || !ShouldSampleDecodingInfoType())
+ return;
+
+ RecordDecodingIdentifiabilityMetric(context, input_token.value(),
+ IdentifiableToken());
+}
+
+base::Optional<IdentifiableToken> ComputeDecodingInfoInputToken(
+ const MediaDecodingConfiguration* input) {
+ if (!IsDecodingInfoTypeAllowed() || !ShouldSampleDecodingInfoType())
+ return base::nullopt;
+
+ return ComputeToken(input);
+}
+
+} // namespace media_capabilities_identifiability_metrics
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.h b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.h
new file mode 100644
index 00000000000..5b2254ca651
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_IDENTIFIABILITY_METRICS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_IDENTIFIABILITY_METRICS_H_
+
+#include "base/optional.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
+
+namespace blink {
+
+class ExecutionContext;
+class MediaCapabilitiesDecodingInfo;
+class MediaDecodingConfiguration;
+
+// Defines methods used to emit UKM events for the identifiability study to
+// determine whether MediaCapabilities::decodingInfo() calls can be used for
+// fingerprinting users and, if so, how much entropy is exposed by the API. Only
+// emits these events when the study is active.
+namespace media_capabilities_identifiability_metrics {
+
+// Reports that a call to decodingInfo() occurred that had the given |input|,
+// resulted in |output| and was performed on the |context|.
+void ReportDecodingInfoResult(ExecutionContext*,
+ const MediaDecodingConfiguration*,
+ const MediaCapabilitiesDecodingInfo*);
+
+// Reports that a call to decodingInfo() occurred that had an input with a
+// digest of |input_token.value()|, resulted in |output| and was performed on
+// the |context|. However, |input_token| should be base::nullopt if the study
+// is not active. These calls should be used when the input object may have
+// been destroyed by the time the output is determined. See
+// ComputeDecodingInfoInputToken below.
+void ReportDecodingInfoResult(ExecutionContext*,
+ base::Optional<IdentifiableToken>,
+ const MediaCapabilitiesDecodingInfo*);
+
+// Returns a digest of the |input| for use in ReportDecodingInfoResult()
+// above. Returns base::nullopt if the identifiability study is not active.
+base::Optional<IdentifiableToken> ComputeDecodingInfoInputToken(
+ const MediaDecodingConfiguration*);
+
+} // namespace media_capabilities_identifiability_metrics
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_IDENTIFIABILITY_METRICS_H_
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 6f563c120c9..567470afecf 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
@@ -206,11 +206,6 @@ void MediaControlInputElement::UpdateShownState() {
parent->SetInlineStyleProperty(CSSPropertyID::kDisplay,
CSSValueID::kNone);
}
-
- // Don't update the shown state of the element if we want to hide
- // icons on the overflow menu.
- if (!RuntimeEnabledFeatures::OverflowIconsForMediaControlsEnabled())
- return;
}
MediaControlElementBase::UpdateShownState();
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.cc
index fdd66cfb18d..94e25c143aa 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h"
#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#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/layout/layout_box_model_object.h"
@@ -114,7 +115,8 @@ void MediaControlSliderElement::SetupBarSegments() {
return;
Element& track = GetTrackElement();
- track.SetShadowPseudoId("-internal-media-controls-segmented-track");
+ track.SetShadowPseudoId(
+ shadow_element_names::kPseudoMediaControlsSegmentedTrack);
// Add the following structure to #track.
//
diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
index 51e5a297294..ec651f364ea 100644
--- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
+++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
@@ -111,7 +111,7 @@ void MediaControlTimelineElement::DefaultEventHandler(Event& event) {
UserMetricsAction("Media.Controls.ScrubbingBegin"));
GetMediaControls().BeginScrubbing(MediaControlsImpl::IsTouchEvent(&event));
Element* thumb = UserAgentShadowRoot()->getElementById(
- shadow_element_names::SliderThumb());
+ shadow_element_names::kIdSliderThumb);
bool started_from_thumb = thumb && thumb == event.target()->ToNode();
metrics_.StartGesture(started_from_thumb);
} else if (EndScrubbingEvent(event)) {
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 82528cb2a73..cdfdb6c926f 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
@@ -728,7 +728,7 @@ TEST_F(MediaControlsImplTest, TimelineMetricsDragFromCurrentPosition) {
DOMRect* thumb_rect =
TimelineElement()
->UserAgentShadowRoot()
- ->getElementById(shadow_element_names::SliderThumb())
+ ->getElementById(shadow_element_names::kIdSliderThumb)
->getBoundingClientRect();
gfx::PointF thumb(thumb_rect->x() + (thumb_rect->width() / 2),
thumb_rect->y() + 1);
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 9ef4ae09ef6..cd37ccb5eda 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
@@ -113,7 +113,7 @@ class MockChromeClientForOrientationLockDelegate final
HeapMojoAssociatedRemote<device::mojom::blink::ScreenOrientation>
screen_orientation(frame.DomWindow());
ScreenOrientationClient().BindPendingReceiver(
- screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ screen_orientation.BindNewEndpointAndPassDedicatedReceiver());
ScreenOrientationController::From(*frame.DomWindow())
->SetScreenOrientationAssociatedRemoteForTests(
std::move(screen_orientation));
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 560e7e0541b..3f3b2aa2c31 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
@@ -56,8 +56,7 @@ class MockChromeClient : public EmptyChromeClient {
EmptyChromeClient::InstallSupplements(frame);
HeapMojoAssociatedRemote<device::mojom::blink::ScreenOrientation>
screen_orientation(frame.DomWindow());
- ignore_result(
- screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ ignore_result(screen_orientation.BindNewEndpointAndPassDedicatedReceiver());
ScreenOrientationController::From(*frame.DomWindow())
->SetScreenOrientationAssociatedRemoteForTests(
std::move(screen_orientation));
diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
index 977182c502a..34ca565a1bb 100644
--- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
+++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
@@ -183,7 +183,7 @@ void CanvasCaptureHandler::SendNewFrame(
if (!image->IsTextureBacked()) {
// Initially try accessing pixels directly if they are in memory.
- sk_sp<SkImage> sk_image = image->PaintImageForCurrentFrame().GetSkImage();
+ sk_sp<SkImage> sk_image = image->PaintImageForCurrentFrame().GetSwSkImage();
SkPixmap pixmap;
if (sk_image->peekPixels(&pixmap) &&
(pixmap.colorType() == kRGBA_8888_SkColorType ||
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 ed4fd492f01..ab283282419 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
@@ -164,7 +164,9 @@ void MediaElementEventListener::Invoke(ExecutionContext* context,
const MediaStreamTrackVector tracks = media_stream_->getTracks();
for (const auto& track : tracks) {
track->stopTrack(context);
- media_stream_->RemoveTrackByComponentAndFireEvents(track->Component());
+ media_stream_->RemoveTrackByComponentAndFireEvents(
+ track->Component(),
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
}
media_stream_->StreamEnded();
@@ -178,17 +180,21 @@ void MediaElementEventListener::Invoke(ExecutionContext* context,
const MediaStreamTrackVector tracks = media_stream_->getTracks();
for (const auto& track : tracks) {
track->stopTrack(context);
- media_stream_->RemoveTrackByComponentAndFireEvents(track->Component());
+ media_stream_->RemoveTrackByComponentAndFireEvents(
+ track->Component(),
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
}
MediaStreamDescriptor* const descriptor = media_element_->GetSrcObject();
DCHECK(descriptor);
for (unsigned i = 0; i < descriptor->NumberOfAudioComponents(); i++) {
media_stream_->AddTrackByComponentAndFireEvents(
- descriptor->AudioComponent(i));
+ descriptor->AudioComponent(i),
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
}
for (unsigned i = 0; i < descriptor->NumberOfVideoComponents(); i++) {
media_stream_->AddTrackByComponentAndFireEvents(
- descriptor->VideoComponent(i));
+ descriptor->VideoComponent(i),
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
}
UpdateSources(context);
return;
@@ -214,12 +220,18 @@ void MediaElementEventListener::Invoke(ExecutionContext* context,
}
MediaStreamComponentVector video_components = descriptor->VideoComponents();
- for (auto component : video_components)
- media_stream_->AddTrackByComponentAndFireEvents(component);
+ for (auto component : video_components) {
+ media_stream_->AddTrackByComponentAndFireEvents(
+ component,
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
+ }
MediaStreamComponentVector audio_components = descriptor->AudioComponents();
- for (auto component : audio_components)
- media_stream_->AddTrackByComponentAndFireEvents(component);
+ for (auto component : audio_components) {
+ media_stream_->AddTrackByComponentAndFireEvents(
+ component,
+ MediaStreamDescriptorClient::DispatchEventTiming::kScheduled);
+ }
DVLOG(2) << "#videotracks: " << video_components.size()
<< " #audiotracks: " << audio_components.size();
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 161cdf8acc2..cf3f588a897 100644
--- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include <limits>
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
-#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
@@ -331,7 +331,8 @@ bool MediaRecorder::isTypeSupported(ExecutionContext* context,
ContentType content_type(type);
bool result = handler->CanSupportMimeType(content_type.GetType(),
content_type.Parameter("codecs"));
- if (IsUserInIdentifiabilityStudy()) {
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kMediaRecorder_IsTypeSupported)) {
blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
.Set(blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
index 4d5217a9ded..b3b7d11e4f3 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediasource/BUILD.gn
@@ -6,14 +6,20 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("mediasource") {
sources = [
+ "cross_thread_media_source_attachment.cc",
+ "cross_thread_media_source_attachment.h",
"html_video_element_media_source.cc",
"html_video_element_media_source.h",
- "media_source_impl.cc",
- "media_source_impl.h",
+ "media_source.cc",
+ "media_source.h",
+ "media_source_attachment_supplement.cc",
+ "media_source_attachment_supplement.h",
"media_source_registry_impl.cc",
"media_source_registry_impl.h",
- "media_source_tracer_impl.cc",
- "media_source_tracer_impl.h",
+ "same_thread_media_source_attachment.cc",
+ "same_thread_media_source_attachment.h",
+ "same_thread_media_source_tracer.cc",
+ "same_thread_media_source_tracer.h",
"source_buffer.cc",
"source_buffer.h",
"source_buffer_list.cc",
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc b/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc
new file mode 100644
index 00000000000..82b2aa9f1d5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc
@@ -0,0 +1,190 @@
+// Copyright 2020 The Chromium Authors. 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/mediasource/cross_thread_media_source_attachment.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
+
+namespace blink {
+
+CrossThreadMediaSourceAttachment::CrossThreadMediaSourceAttachment(
+ MediaSource* media_source,
+ util::PassKey<URLMediaSource> /* passkey */)
+ : registered_media_source_(media_source) {
+ // This kind of attachment can only be constructed by the worker thread.
+ DCHECK(!IsMainThread());
+
+ DVLOG(1) << __func__ << " this=" << this << " media_source=" << media_source;
+
+ // Verify that at construction time, refcounting of this object begins at
+ // precisely 1.
+ DCHECK(HasOneRef());
+}
+
+CrossThreadMediaSourceAttachment::~CrossThreadMediaSourceAttachment() {
+ DVLOG(1) << __func__ << " this=" << this;
+}
+
+void CrossThreadMediaSourceAttachment::NotifyDurationChanged(
+ MediaSourceTracer* tracer,
+ double duration) {
+ // Called only by the MSE API on worker thread.
+ DCHECK(!IsMainThread());
+
+ DVLOG(1) << __func__ << " this=" << this;
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+double CrossThreadMediaSourceAttachment::GetRecentMediaTime(
+ MediaSourceTracer* tracer) {
+ // Called only by the MSE API on worker thread.
+ DCHECK(!IsMainThread());
+
+ DVLOG(1) << __func__ << " this=" << this;
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+ return 0.0;
+}
+
+bool CrossThreadMediaSourceAttachment::GetElementError(
+ MediaSourceTracer* tracer) {
+ // Called only by the MSE API on worker thread.
+ DCHECK(!IsMainThread());
+
+ DVLOG(1) << __func__ << " this=" << this;
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+ return true;
+}
+
+void CrossThreadMediaSourceAttachment::Unregister() {
+ DVLOG(1) << __func__ << " this=" << this
+ << ", IsMainThread=" << IsMainThread();
+
+ // The only expected caller is a MediaSourceRegistryImpl on the main thread
+ // (or possibly on the worker thread, if MediaSourceInWorkers is enabled).
+ DCHECK(IsMainThread() ||
+ RuntimeEnabledFeatures::MediaSourceInWorkersEnabled());
+
+ // Release our strong reference to the MediaSource. Note that revokeObjectURL
+ // of the url associated with this attachment could commonly follow this path
+ // while the MediaSource (and any attachment to an HTMLMediaElement) may still
+ // be alive/active. Also note that |registered_media_source_| could be
+ // incorrectly cleared already if its owner's execution context destruction
+ // has completed without notifying us, hence careful locking in
+ // MediaSourceRegistryImpl around this scenario, and allowance for us to be
+ // called on the worker context. Locking there instead of cross-thread posting
+ // to the main thread to reach us enables stability in cases where worker's
+ // context destruction or explicit object URL revocation from worker context
+ // races attempted usage of the object URL (or |registered_media_source_|
+ // here).
+ DCHECK(registered_media_source_);
+ registered_media_source_ = nullptr;
+}
+
+MediaSourceTracer*
+CrossThreadMediaSourceAttachment::StartAttachingToMediaElement(
+ HTMLMediaElement* element,
+ bool* success) {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ DCHECK(success);
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+ *success = false;
+ return nullptr;
+}
+
+void CrossThreadMediaSourceAttachment::CompleteAttachingToMediaElement(
+ MediaSourceTracer* tracer,
+ std::unique_ptr<WebMediaSource> web_media_source) {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+void CrossThreadMediaSourceAttachment::Close(MediaSourceTracer* tracer) {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+WebTimeRanges CrossThreadMediaSourceAttachment::BufferedInternal(
+ MediaSourceTracer* tracer) const {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+ return {};
+}
+
+WebTimeRanges CrossThreadMediaSourceAttachment::SeekableInternal(
+ MediaSourceTracer* tracer) const {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+ return {};
+}
+
+void CrossThreadMediaSourceAttachment::OnTrackChanged(MediaSourceTracer* tracer,
+ TrackBase* track) {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+void CrossThreadMediaSourceAttachment::OnElementTimeUpdate(double time) {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ DVLOG(3) << __func__ << " this=" << this << ", time=" << time;
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+void CrossThreadMediaSourceAttachment::OnElementError() {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ DVLOG(3) << __func__ << " this=" << this;
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+void CrossThreadMediaSourceAttachment::OnElementContextDestroyed() {
+ // Called only by the media element on main thread.
+ DCHECK(IsMainThread());
+
+ DVLOG(3) << __func__ << " this=" << this;
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+void CrossThreadMediaSourceAttachment::OnMediaSourceContextDestroyed() {
+ // Called only by the MSE API on worker thread.
+ DCHECK(!IsMainThread());
+
+ DVLOG(3) << __func__ << " this=" << this;
+ // TODO(https://crbug.com/878133): Implement cross-thread behavior for this.
+ NOTIMPLEMENTED();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h b/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h
new file mode 100644
index 00000000000..bed3906ade2
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_CROSS_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_CROSS_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
+
+#include <memory>
+
+#include "base/util/type_safety/pass_key.h"
+#include "third_party/blink/public/platform/web_time_range.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
+#include "third_party/blink/renderer/modules/mediasource/url_media_source.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+// Concrete attachment that supports operation between a media element on the
+// main thread and the MSE API on a dedicated worker thread.
+// TODO(https://crbug.com/878133): Implement this more fully. Currently it is
+// implementing only the constructor, necessary for cross-thread registry
+// implementation and basic verification.
+class CrossThreadMediaSourceAttachment final
+ : public MediaSourceAttachmentSupplement {
+ public:
+ // The only intended caller of this constructor is
+ // URLMediaSource::createObjectUrl (as shown by using the PassKey), executing
+ // in the worker thread context. The raw pointer is then adopted into a
+ // scoped_refptr in MediaSourceRegistryImpl::RegisterURL.
+ CrossThreadMediaSourceAttachment(MediaSource* media_source,
+ util::PassKey<URLMediaSource>);
+
+ // MediaSourceAttachmentSupplement, called by MSE API on worker thread.
+ void NotifyDurationChanged(MediaSourceTracer* tracer, double duration) final;
+ double GetRecentMediaTime(MediaSourceTracer* tracer) final;
+ bool GetElementError(MediaSourceTracer* tracer) final;
+ void OnMediaSourceContextDestroyed() final;
+
+ // MediaSourceAttachment methods called on main thread by media element,
+ // except Unregister is called on either main or dedicated worker thread by
+ // MediaSourceRegistryImpl.
+ void Unregister() final;
+ MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*,
+ bool* success) final;
+ void CompleteAttachingToMediaElement(MediaSourceTracer* tracer,
+ std::unique_ptr<WebMediaSource>) final;
+
+ void Close(MediaSourceTracer* tracer) final;
+ WebTimeRanges BufferedInternal(MediaSourceTracer* tracer) const final;
+ WebTimeRanges SeekableInternal(MediaSourceTracer* tracer) const final;
+ void OnTrackChanged(MediaSourceTracer* tracer, TrackBase*) final;
+
+ void OnElementTimeUpdate(double time) final;
+ void OnElementError() final;
+ void OnElementContextDestroyed() final;
+
+ private:
+ ~CrossThreadMediaSourceAttachment() override;
+
+ // Cache of the registered worker-thread MediaSource. Retains strong reference
+ // on all Oilpan heaps, from construction of this object until Unregister() is
+ // called. This lets the main thread successfully attach (modulo normal
+ // reasons why StartAttaching..() can fail) to the worker-thread MediaSource
+ // even if there were no other strong references other than this one on the
+ // worker-thread Oilpan heap to the MediaSource.
+ CrossThreadPersistent<MediaSource> registered_media_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrossThreadMediaSourceAttachment);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_CROSS_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
index 497e4075836..81a68d896a2 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -1,34 +1,8 @@
-/*
- * 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.
- */
-
-#include "third_party/blink/renderer/modules/mediasource/media_source_impl.h"
+// Copyright 2020 The Chromium Authors. 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/mediasource/media_source.h"
#include <memory>
@@ -36,7 +10,7 @@
#include "base/metrics/histogram_functions.h"
#include "media/base/logging_override_if_enabled.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
-#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/platform/web_media_source.h"
#include "third_party/blink/public/platform/web_source_buffer.h"
@@ -46,7 +20,7 @@
#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"
-#include "third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h"
#include "third_party/blink/renderer/modules/mediasource/source_buffer_track_base_supplement.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -69,21 +43,36 @@ namespace {
enum class MseExecutionContext {
kWindow = 0,
- // TODO(wolenetz): Support MSE usage in dedicated workers. See
- // https://crbug.com/878133.
kDedicatedWorker = 1,
- // TODO(wolenetz): Consider supporting MSE usage in SharedWorkers. See
- // https://crbug.com/1054566.
+ // TODO(https://crbug.com/1054566): Consider supporting MSE usage in
+ // SharedWorkers.
kSharedWorker = 2,
kMaxValue = kSharedWorker
};
} // namespace
+static AtomicString ReadyStateToString(MediaSource::ReadyState state) {
+ AtomicString result;
+ switch (state) {
+ case MediaSource::ReadyState::kOpen:
+ result = "open";
+ break;
+ case MediaSource::ReadyState::kClosed:
+ result = "closed";
+ break;
+ case MediaSource::ReadyState::kEnded:
+ result = "ended";
+ break;
+ }
+
+ return result;
+}
+
static bool ThrowExceptionIfClosed(bool is_open,
ExceptionState& exception_state) {
if (!is_open) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The MediaSource's readyState is not 'open'.");
return true;
@@ -99,7 +88,7 @@ static bool ThrowExceptionIfClosedOrUpdating(bool is_open,
return true;
if (is_updating) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The 'updating' attribute is true on one or more of this MediaSource's "
"SourceBuffers.");
@@ -109,28 +98,13 @@ static bool ThrowExceptionIfClosedOrUpdating(bool is_open,
return false;
}
-const AtomicString& MediaSourceImpl::OpenKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, open, ("open"));
- return open;
+MediaSource* MediaSource::Create(ExecutionContext* context) {
+ return MakeGarbageCollected<MediaSource>(context);
}
-const AtomicString& MediaSourceImpl::ClosedKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, closed, ("closed"));
- return closed;
-}
-
-const AtomicString& MediaSourceImpl::EndedKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, ended, ("ended"));
- return ended;
-}
-
-MediaSourceImpl* MediaSourceImpl::Create(ExecutionContext* context) {
- return MakeGarbageCollected<MediaSourceImpl>(context);
-}
-
-MediaSourceImpl::MediaSourceImpl(ExecutionContext* context)
+MediaSource::MediaSource(ExecutionContext* context)
: ExecutionContextLifecycleObserver(context),
- ready_state_(ClosedKeyword()),
+ ready_state_(ReadyState::kClosed),
async_event_queue_(
MakeGarbageCollected<EventQueue>(context,
TaskType::kMediaElementEvent)),
@@ -158,35 +132,33 @@ MediaSourceImpl::MediaSourceImpl(ExecutionContext* context)
}
base::UmaHistogramEnumeration("Media.MSE.ExecutionContext", type);
- // TODO(wolenetz): Actually enable experimental usage of MediaSource API from
- // dedicated worker contexts. See https://crbug.com/878133.
- // TODO(wolenetz): Also consider supporting experimental usage of MediaSource
- // API from shared worker contexts. See https://crbug.com/1054566.
- CHECK(type == MseExecutionContext::kWindow)
- << "MSE is not yet supported from workers";
+ // TODO(https://crbug.com/1054566): Also consider supporting experimental
+ // usage of MediaSource API from shared worker contexts. Meanwhile, IDL limits
+ // constructor exposure to not include shared worker.
+ CHECK_NE(type, MseExecutionContext::kSharedWorker)
+ << "MSE is not supported from SharedWorkers";
}
-MediaSourceImpl::~MediaSourceImpl() {
+MediaSource::~MediaSource() {
DVLOG(1) << __func__ << " this=" << this;
}
-void MediaSourceImpl::LogAndThrowDOMException(ExceptionState& exception_state,
- DOMExceptionCode error,
- const String& message) {
+void MediaSource::LogAndThrowDOMException(ExceptionState& exception_state,
+ DOMExceptionCode error,
+ const String& message) {
DVLOG(1) << __func__ << " (error=" << ToExceptionCode(error)
<< ", message=" << message << ")";
exception_state.ThrowDOMException(error, message);
}
-void MediaSourceImpl::LogAndThrowTypeError(ExceptionState& exception_state,
- const String& message) {
+void MediaSource::LogAndThrowTypeError(ExceptionState& exception_state,
+ const String& message) {
DVLOG(1) << __func__ << " (message=" << message << ")";
exception_state.ThrowTypeError(message);
}
-SourceBuffer* MediaSourceImpl::addSourceBuffer(
- const String& type,
- ExceptionState& exception_state) {
+SourceBuffer* MediaSource::addSourceBuffer(const String& type,
+ ExceptionState& exception_state) {
DVLOG(2) << __func__ << " this=" << this << " type=" << type;
// 2.2
@@ -266,8 +238,8 @@ SourceBuffer* MediaSourceImpl::addSourceBuffer(
return buffer;
}
-void MediaSourceImpl::removeSourceBuffer(SourceBuffer* buffer,
- ExceptionState& exception_state) {
+void MediaSource::removeSourceBuffer(SourceBuffer* buffer,
+ ExceptionState& exception_state) {
DVLOG(2) << __func__ << " this=" << this << " buffer=" << buffer;
// 2.2
@@ -298,14 +270,14 @@ void MediaSourceImpl::removeSourceBuffer(SourceBuffer* buffer,
// SourceBuffer::removedFromMediaSource (steps 2-8) above.
}
-void MediaSourceImpl::OnReadyStateChange(const AtomicString& old_state,
- const AtomicString& new_state) {
+void MediaSource::OnReadyStateChange(const ReadyState old_state,
+ const ReadyState new_state) {
if (IsOpen()) {
ScheduleEvent(event_type_names::kSourceopen);
return;
}
- if (old_state == OpenKeyword() && new_state == EndedKeyword()) {
+ if (old_state == ReadyState::kOpen && new_state == ReadyState::kEnded) {
ScheduleEvent(event_type_names::kSourceended);
return;
}
@@ -320,11 +292,13 @@ void MediaSourceImpl::OnReadyStateChange(const AtomicString& old_state,
source_buffers_->Clear();
attached_element_.Clear();
+ media_source_attachment_.reset();
+ attachment_tracer_ = nullptr;
ScheduleEvent(event_type_names::kSourceclose);
}
-bool MediaSourceImpl::IsUpdating() const {
+bool MediaSource::IsUpdating() const {
// Return true if any member of |m_sourceBuffers| is updating.
for (unsigned i = 0; i < source_buffers_->length(); ++i) {
if (source_buffers_->item(i)->updating())
@@ -335,8 +309,8 @@ bool MediaSourceImpl::IsUpdating() const {
}
// static
-bool MediaSourceImpl::isTypeSupported(ExecutionContext* context,
- const String& type) {
+bool MediaSource::isTypeSupported(ExecutionContext* context,
+ const String& type) {
// Section 2.2 isTypeSupported() method steps.
// https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-MediaSource-isTypeSupported-boolean-DOMString-type
// 1. If type is an empty string, then return false.
@@ -362,8 +336,7 @@ bool MediaSourceImpl::isTypeSupported(ExecutionContext* context,
MIMETypeRegistry::kIsNotSupported) {
DVLOG(1) << __func__ << "(" << type
<< ") -> false (not supported by HTMLMediaElement)";
- if (IsUserInIdentifiabilityStudy())
- RecordIdentifiabilityMetric(context, type, false);
+ RecordIdentifiabilityMetric(context, type, false);
return false;
}
@@ -386,14 +359,17 @@ bool MediaSourceImpl::isTypeSupported(ExecutionContext* context,
MIMETypeRegistry::SupportsMediaSourceMIMEType(
content_type.GetType(), codecs);
DVLOG(2) << __func__ << "(" << type << ") -> " << (result ? "true" : "false");
- if (IsUserInIdentifiabilityStudy())
- RecordIdentifiabilityMetric(context, type, result);
+ RecordIdentifiabilityMetric(context, type, result);
return result;
}
-void MediaSourceImpl::RecordIdentifiabilityMetric(ExecutionContext* context,
- const String& type,
- bool result) {
+void MediaSource::RecordIdentifiabilityMetric(ExecutionContext* context,
+ const String& type,
+ bool result) {
+ if (!IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kMediaSource_IsTypeSupported)) {
+ return;
+ }
blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
.Set(blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::kMediaSource_IsTypeSupported,
@@ -402,16 +378,17 @@ void MediaSourceImpl::RecordIdentifiabilityMetric(ExecutionContext* context,
.Record(context->UkmRecorder());
}
-const AtomicString& MediaSourceImpl::InterfaceName() const {
+const AtomicString& MediaSource::InterfaceName() const {
return event_target_names::kMediaSource;
}
-ExecutionContext* MediaSourceImpl::GetExecutionContext() const {
+ExecutionContext* MediaSource::GetExecutionContext() const {
return ExecutionContextLifecycleObserver::GetExecutionContext();
}
-void MediaSourceImpl::Trace(Visitor* visitor) const {
+void MediaSource::Trace(Visitor* visitor) const {
visitor->Trace(async_event_queue_);
+ visitor->Trace(attachment_tracer_);
visitor->Trace(attached_element_);
visitor->Trace(source_buffers_);
visitor->Trace(active_source_buffers_);
@@ -420,24 +397,27 @@ void MediaSourceImpl::Trace(Visitor* visitor) const {
ExecutionContextLifecycleObserver::Trace(visitor);
}
-void MediaSourceImpl::CompleteAttachingToMediaElement(
+void MediaSource::CompleteAttachingToMediaElement(
std::unique_ptr<WebMediaSource> web_media_source) {
- TRACE_EVENT_NESTABLE_ASYNC_END0(
- "media", "MediaSourceImpl::StartAttachingToMediaElement",
- TRACE_ID_LOCAL(this));
+ TRACE_EVENT_NESTABLE_ASYNC_END0("media",
+ "MediaSource::StartAttachingToMediaElement",
+ TRACE_ID_LOCAL(this));
DCHECK(web_media_source);
DCHECK(!web_media_source_);
DCHECK(attached_element_);
+ DCHECK(media_source_attachment_);
+ DCHECK(attachment_tracer_);
+
web_media_source_ = std::move(web_media_source);
- SetReadyState(OpenKeyword());
+ SetReadyState(ReadyState::kOpen);
}
-double MediaSourceImpl::duration() const {
+double MediaSource::duration() const {
return IsClosed() ? std::numeric_limits<float>::quiet_NaN()
: web_media_source_->Duration();
}
-WebTimeRanges MediaSourceImpl::BufferedInternal() const {
+WebTimeRanges MediaSource::BufferedInternal() const {
// Implements MediaSource algorithm for HTMLMediaElement.buffered.
// https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
Vector<WebTimeRanges> ranges(active_source_buffers_->length());
@@ -470,7 +450,7 @@ WebTimeRanges MediaSourceImpl::BufferedInternal() const {
// 5. For each SourceBuffer object in activeSourceBuffers run the following
// steps:
- bool ended = readyState() == EndedKeyword();
+ bool ended = ready_state_ == ReadyState::kEnded;
// 5.1 Let source ranges equal the ranges returned by the buffered attribute
// on the current SourceBuffer.
for (WebTimeRanges& source_ranges : ranges) {
@@ -489,12 +469,12 @@ WebTimeRanges MediaSourceImpl::BufferedInternal() const {
return intersection_ranges;
}
-TimeRanges* MediaSourceImpl::Buffered() const {
+TimeRanges* MediaSource::Buffered() const {
return MakeGarbageCollected<TimeRanges>(BufferedInternal());
}
-WebTimeRanges MediaSourceImpl::SeekableInternal() const {
- DCHECK(attached_element_)
+WebTimeRanges MediaSource::SeekableInternal() const {
+ DCHECK(attached_element_ && media_source_attachment_ && attachment_tracer_)
<< "Seekable should only be used when attached to HTMLMediaElement";
// Implements MediaSource algorithm for HTMLMediaElement.seekable.
@@ -548,7 +528,7 @@ WebTimeRanges MediaSourceImpl::SeekableInternal() const {
return ranges;
}
-void MediaSourceImpl::OnTrackChanged(TrackBase* track) {
+void MediaSource::OnTrackChanged(TrackBase* track) {
DCHECK(HTMLMediaElement::MediaTracksEnabledInternally());
SourceBuffer* source_buffer =
SourceBufferTrackBaseSupplement::sourceBuffer(*track);
@@ -569,8 +549,8 @@ void MediaSourceImpl::OnTrackChanged(TrackBase* track) {
SetSourceBufferActive(source_buffer, is_active);
}
-void MediaSourceImpl::setDuration(double duration,
- ExceptionState& exception_state) {
+void MediaSource::setDuration(double duration,
+ ExceptionState& exception_state) {
DVLOG(3) << __func__ << " this=" << this << " : duration=" << duration;
// 2.1 https://www.w3.org/TR/media-source/#widl-MediaSource-duration
@@ -601,8 +581,8 @@ void MediaSourceImpl::setDuration(double duration,
DurationChangeAlgorithm(duration, exception_state);
}
-void MediaSourceImpl::DurationChangeAlgorithm(double new_duration,
- ExceptionState& exception_state) {
+void MediaSource::DurationChangeAlgorithm(double new_duration,
+ ExceptionState& exception_state) {
// http://w3c.github.io/media-source/#duration-change-algorithm
// 1. If the current value of duration is equal to new duration, then return.
if (new_duration == duration())
@@ -633,7 +613,7 @@ void MediaSourceImpl::DurationChangeAlgorithm(double new_duration,
}
Deprecation::CountDeprecation(
- attached_element_->GetExecutionContext(),
+ GetExecutionContext(),
WebFeature::kMediaSourceDurationTruncatingBuffered);
// See also deprecated remove(new duration, old duration) behavior below.
}
@@ -644,7 +624,6 @@ void MediaSourceImpl::DurationChangeAlgorithm(double new_duration,
std::isnan(old_duration) ? 0 : old_duration);
// 4. Update duration to new duration.
- bool request_seek = attached_element_->currentTime() > new_duration;
web_media_source_->SetDuration(new_duration);
if (!RuntimeEnabledFeatures::MediaSourceNewAbortAndDurationEnabled() &&
@@ -652,9 +631,10 @@ void MediaSourceImpl::DurationChangeAlgorithm(double new_duration,
// Deprecated behavior: if the new duration is less than old duration,
// then call remove(new duration, old duration) on all all objects in
// sourceBuffers.
- for (unsigned i = 0; i < source_buffers_->length(); ++i)
+ for (unsigned i = 0; i < source_buffers_->length(); ++i) {
source_buffers_->item(i)->remove(new_duration, old_duration,
ASSERT_NO_EXCEPTION);
+ }
}
// 5. If a user agent is unable to partially render audio frames or text cues
@@ -666,18 +646,20 @@ void MediaSourceImpl::DurationChangeAlgorithm(double new_duration,
// 6. Update the media controller duration to new duration and run the
// HTMLMediaElement duration change algorithm.
- attached_element_->DurationChanged(new_duration, request_seek);
+ media_source_attachment_->NotifyDurationChanged(attachment_tracer_,
+ new_duration);
}
-void MediaSourceImpl::SetReadyState(const AtomicString& state) {
- DCHECK(state == OpenKeyword() || state == ClosedKeyword() ||
- state == EndedKeyword());
+void MediaSource::SetReadyState(const ReadyState state) {
+ DCHECK(state == ReadyState::kOpen || state == ReadyState::kClosed ||
+ state == ReadyState::kEnded);
- AtomicString old_state = readyState();
- DVLOG(3) << __func__ << " this=" << this << " : " << old_state << " -> "
- << state;
+ ReadyState old_state = ready_state_;
+ DVLOG(3) << __func__ << " this=" << this << " : "
+ << ReadyStateToString(old_state) << " -> "
+ << ReadyStateToString(state);
- if (state == ClosedKeyword()) {
+ if (state == ReadyState::kClosed) {
web_media_source_.reset();
}
@@ -689,11 +671,12 @@ void MediaSourceImpl::SetReadyState(const AtomicString& state) {
OnReadyStateChange(old_state, state);
}
-void MediaSourceImpl::endOfStream(const AtomicString& error,
- ExceptionState& exception_state) {
- DEFINE_STATIC_LOCAL(const AtomicString, network, ("network"));
- DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode"));
+AtomicString MediaSource::readyState() const {
+ return ReadyStateToString(ready_state_);
+}
+void MediaSource::endOfStream(const AtomicString& error,
+ ExceptionState& exception_state) {
DVLOG(3) << __func__ << " this=" << this << " : error=" << error;
// https://www.w3.org/TR/media-source/#dom-mediasource-endofstream
@@ -706,21 +689,21 @@ void MediaSourceImpl::endOfStream(const AtomicString& error,
return;
// 3. Run the end of stream algorithm with the error parameter set to error.
- if (error == network)
+ if (error == "network")
EndOfStreamAlgorithm(WebMediaSource::kEndOfStreamStatusNetworkError);
- else if (error == decode)
+ else if (error == "decode")
EndOfStreamAlgorithm(WebMediaSource::kEndOfStreamStatusDecodeError);
else // "" is allowed internally but not by IDL bindings.
EndOfStreamAlgorithm(WebMediaSource::kEndOfStreamStatusNoError);
}
-void MediaSourceImpl::endOfStream(ExceptionState& exception_state) {
+void MediaSource::endOfStream(ExceptionState& exception_state) {
endOfStream("", exception_state);
}
-void MediaSourceImpl::setLiveSeekableRange(double start,
- double end,
- ExceptionState& exception_state) {
+void MediaSource::setLiveSeekableRange(double start,
+ double end,
+ ExceptionState& exception_state) {
DVLOG(3) << __func__ << " this=" << this << " : start=" << start
<< ", end=" << end;
@@ -752,7 +735,7 @@ void MediaSourceImpl::setLiveSeekableRange(double start,
live_seekable_range_ = MakeGarbageCollected<TimeRanges>(start, end);
}
-void MediaSourceImpl::clearLiveSeekableRange(ExceptionState& exception_state) {
+void MediaSource::clearLiveSeekableRange(ExceptionState& exception_state) {
DVLOG(3) << __func__ << " this=" << this;
// http://w3c.github.io/media-source/#widl-MediaSource-clearLiveSeekableRange-void
@@ -772,12 +755,12 @@ void MediaSourceImpl::clearLiveSeekableRange(ExceptionState& exception_state) {
live_seekable_range_ = MakeGarbageCollected<TimeRanges>();
}
-bool MediaSourceImpl::IsOpen() const {
- return readyState() == OpenKeyword();
+bool MediaSource::IsOpen() const {
+ return ready_state_ == ReadyState::kOpen;
}
-void MediaSourceImpl::SetSourceBufferActive(SourceBuffer* source_buffer,
- bool is_active) {
+void MediaSource::SetSourceBufferActive(SourceBuffer* source_buffer,
+ bool is_active) {
if (!is_active) {
DCHECK(active_source_buffers_->Contains(source_buffer));
active_source_buffers_->Remove(source_buffer);
@@ -806,26 +789,34 @@ void MediaSourceImpl::SetSourceBufferActive(SourceBuffer* source_buffer,
active_source_buffers_->insert(insert_position, source_buffer);
}
-HTMLMediaElement* MediaSourceImpl::MediaElement() const {
+// TODO(https://crbug.com/878133): Remove this getter and instead rely on
+// Attachment() to communicate about the media element.
+HTMLMediaElement* MediaSource::MediaElement() const {
return attached_element_.Get();
}
-void MediaSourceImpl::EndOfStreamAlgorithm(
+std::pair<scoped_refptr<MediaSourceAttachmentSupplement>, MediaSourceTracer*>
+MediaSource::AttachmentAndTracer() const {
+ return std::make_pair(media_source_attachment_, attachment_tracer_);
+}
+
+void MediaSource::EndOfStreamAlgorithm(
const WebMediaSource::EndOfStreamStatus eos_status) {
// https://www.w3.org/TR/media-source/#end-of-stream-algorithm
// 1. Change the readyState attribute value to "ended".
// 2. Queue a task to fire a simple event named sourceended at the
// MediaSource.
- SetReadyState(EndedKeyword());
+ SetReadyState(ReadyState::kEnded);
// 3. Do various steps based on |eos_status|.
web_media_source_->MarkEndOfStream(eos_status);
if (eos_status == WebMediaSource::kEndOfStreamStatusNoError) {
// The implementation may not have immediately informed the
- // |attached_element_| of the potentially reduced duration. Prevent
- // app-visible duration race by synchronously running the duration change
- // algorithm. The MSE spec supports this:
+ // |attached_element_| (or the element known by the |attachment_tracer_|
+ // for the current |media_source_attachment_|) of the potentially reduced
+ // duration. Prevent app-visible duration race by synchronously running the
+ // duration change algorithm. The MSE spec supports this:
// https://www.w3.org/TR/media-source/#end-of-stream-algorithm
// 2.4.7.3 (If error is not set)
// Run the duration change algorithm with new duration set to the largest
@@ -839,42 +830,51 @@ void MediaSourceImpl::EndOfStreamAlgorithm(
// to just mark end of stream, and move the duration reduction logic to here
// so we can just run DurationChangeAlgorithm(...) here.
double new_duration = duration();
- bool request_seek = attached_element_->currentTime() > new_duration;
- attached_element_->DurationChanged(new_duration, request_seek);
+ media_source_attachment_->NotifyDurationChanged(attachment_tracer_,
+ new_duration);
}
}
-bool MediaSourceImpl::IsClosed() const {
- return readyState() == ClosedKeyword();
+bool MediaSource::IsClosed() const {
+ return ready_state_ == ReadyState::kClosed;
}
-void MediaSourceImpl::Close() {
- SetReadyState(ClosedKeyword());
+void MediaSource::Close() {
+ SetReadyState(ReadyState::kClosed);
}
-MediaSourceTracer* MediaSourceImpl::StartAttachingToMediaElement(
+MediaSourceTracer* MediaSource::StartAttachingToMediaElement(
+ scoped_refptr<MediaSourceAttachmentSupplement> attachment,
HTMLMediaElement* element) {
- if (attached_element_)
+ if (attached_element_) {
+ DCHECK(media_source_attachment_);
+ DCHECK(attachment_tracer_);
return nullptr;
+ }
+ DCHECK(!media_source_attachment_);
+ DCHECK(!attachment_tracer_);
DCHECK(IsClosed());
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
- "media", "MediaSourceImpl::StartAttachingToMediaElement",
- TRACE_ID_LOCAL(this));
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("media",
+ "MediaSource::StartAttachingToMediaElement",
+ TRACE_ID_LOCAL(this));
attached_element_ = element;
- return MakeGarbageCollected<MediaSourceTracerImpl>(element, this);
+ media_source_attachment_ = attachment;
+ attachment_tracer_ =
+ MakeGarbageCollected<SameThreadMediaSourceTracer>(element, this);
+ return attachment_tracer_;
}
-void MediaSourceImpl::OpenIfInEndedState() {
- if (ready_state_ != EndedKeyword())
+void MediaSource::OpenIfInEndedState() {
+ if (ready_state_ != ReadyState::kEnded)
return;
- SetReadyState(OpenKeyword());
+ SetReadyState(ReadyState::kOpen);
web_media_source_->UnmarkEndOfStream();
}
-bool MediaSourceImpl::HasPendingActivity() const {
+bool MediaSource::HasPendingActivity() const {
// 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
@@ -886,13 +886,16 @@ bool MediaSourceImpl::HasPendingActivity() const {
return async_event_queue_->HasPendingEvents();
}
-void MediaSourceImpl::ContextDestroyed() {
+void MediaSource::ContextDestroyed() {
+ DVLOG(1) << __func__ << " this=" << this;
+ if (media_source_attachment_)
+ media_source_attachment_->OnMediaSourceContextDestroyed();
if (!IsClosed())
- SetReadyState(ClosedKeyword());
+ SetReadyState(ReadyState::kClosed);
web_media_source_.reset();
}
-std::unique_ptr<WebSourceBuffer> MediaSourceImpl::CreateWebSourceBuffer(
+std::unique_ptr<WebSourceBuffer> MediaSource::CreateWebSourceBuffer(
const String& type,
const String& codecs,
ExceptionState& exception_state) {
@@ -931,7 +934,7 @@ std::unique_ptr<WebSourceBuffer> MediaSourceImpl::CreateWebSourceBuffer(
return nullptr;
}
-void MediaSourceImpl::ScheduleEvent(const AtomicString& event_name) {
+void MediaSource::ScheduleEvent(const AtomicString& event_name) {
DCHECK(async_event_queue_);
Event* event = Event::Create(event_name);
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
index 4caec136a10..f39e0a3370e 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_impl.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.h
@@ -1,77 +1,64 @@
-/*
- * 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_MODULES_MEDIASOURCE_MEDIA_SOURCE_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_IMPL_H_
+// Copyright 2020 The Chromium Authors. 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_MEDIASOURCE_MEDIA_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_H_
#include <memory>
+#include <tuple>
+#include <utility>
+#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/platform/web_media_source.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/html/media/media_source.h"
#include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
#include "third_party/blink/renderer/core/html/time_ranges.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
#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/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
class EventQueue;
class ExceptionState;
+class HTMLMediaElement;
+class MediaSourceAttachmentSupplement;
+class TrackBase;
class WebSourceBuffer;
-class MediaSourceImpl final : public EventTargetWithInlineData,
- public MediaSource,
- public ActiveScriptWrappable<MediaSourceImpl>,
- public ExecutionContextLifecycleObserver {
+// Media Source Extensions (MSE) API's MediaSource object implementation (see
+// also https://w3.org/TR/media-source/). Web apps can extend an
+// HTMLMediaElement's instance to use the MSE API (also known as "attaching MSE
+// to a media element") by using a Media Source object URL as the media
+// element's src attribute or the src attribute of a <source> inside the media
+// element. A MediaSourceAttachmentSupplement encapsulates the linkage of that
+// object URL to a MediaSource instance, and allows communication between the
+// media element and the MSE API.
+class MediaSource final : public EventTargetWithInlineData,
+ public ActiveScriptWrappable<MediaSource>,
+ public ExecutionContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO();
public:
- static const AtomicString& OpenKeyword();
- static const AtomicString& ClosedKeyword();
- static const AtomicString& EndedKeyword();
+ enum class ReadyState { kOpen, kClosed, kEnded };
- static MediaSourceImpl* Create(ExecutionContext*);
+ static MediaSource* Create(ExecutionContext*);
- explicit MediaSourceImpl(ExecutionContext*);
- ~MediaSourceImpl() override;
+ explicit MediaSource(ExecutionContext*);
+ ~MediaSource() override;
static void LogAndThrowDOMException(ExceptionState&,
DOMExceptionCode error,
const String& message);
static void LogAndThrowTypeError(ExceptionState&, const String&);
- // MediaSource.idl methods
+ // Web-exposed methods from media_source.idl
SourceBufferList* sourceBuffers() { return source_buffers_.Get(); }
SourceBufferList* activeSourceBuffers() {
return active_source_buffers_.Get();
@@ -84,7 +71,7 @@ class MediaSourceImpl final : public EventTargetWithInlineData,
DEFINE_ATTRIBUTE_EVENT_LISTENER(sourceended, kSourceended)
DEFINE_ATTRIBUTE_EVENT_LISTENER(sourceclose, kSourceclose)
- const AtomicString& readyState() const { return ready_state_; }
+ AtomicString readyState() const;
void endOfStream(const AtomicString& error, ExceptionState&);
void endOfStream(ExceptionState&);
void setLiveSeekableRange(double start, double end, ExceptionState&);
@@ -92,17 +79,19 @@ class MediaSourceImpl final : public EventTargetWithInlineData,
static bool isTypeSupported(ExecutionContext* context, const String& type);
- // html/media/MediaSource interface implementation
- MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*) override;
- void CompleteAttachingToMediaElement(
- std::unique_ptr<WebMediaSource>) override;
- void Close() override;
- bool IsClosed() const override;
- double duration() const override;
- WebTimeRanges BufferedInternal() const override;
- WebTimeRanges SeekableInternal() const override;
- TimeRanges* Buffered() const override;
- void OnTrackChanged(TrackBase*) override;
+ // Methods needed by a MediaSourceAttachmentSupplement to service operations
+ // proxied from an HTMLMediaElement.
+ MediaSourceTracer* StartAttachingToMediaElement(
+ scoped_refptr<MediaSourceAttachmentSupplement> attachment,
+ HTMLMediaElement* element);
+ void CompleteAttachingToMediaElement(std::unique_ptr<WebMediaSource>);
+ void Close();
+ bool IsClosed() const;
+ double duration() const;
+ WebTimeRanges BufferedInternal() const;
+ WebTimeRanges SeekableInternal() const;
+ TimeRanges* Buffered() const;
+ void OnTrackChanged(TrackBase*);
// EventTarget interface
const AtomicString& InterfaceName() const override;
@@ -119,13 +108,16 @@ class MediaSourceImpl final : public EventTargetWithInlineData,
bool IsOpen() const;
void SetSourceBufferActive(SourceBuffer*, bool);
HTMLMediaElement* MediaElement() const;
+ std::pair<scoped_refptr<MediaSourceAttachmentSupplement>, MediaSourceTracer*>
+ AttachmentAndTracer() const;
void EndOfStreamAlgorithm(const WebMediaSource::EndOfStreamStatus);
void Trace(Visitor*) const override;
private:
- void SetReadyState(const AtomicString&);
- void OnReadyStateChange(const AtomicString&, const AtomicString&);
+ void SetReadyState(const ReadyState state);
+ void OnReadyStateChange(const ReadyState old_state,
+ const ReadyState new_state);
bool IsUpdating() const;
@@ -142,16 +134,24 @@ class MediaSourceImpl final : public EventTargetWithInlineData,
void DurationChangeAlgorithm(double new_duration, ExceptionState&);
std::unique_ptr<WebMediaSource> web_media_source_;
- AtomicString ready_state_;
+ ReadyState ready_state_;
Member<EventQueue> async_event_queue_;
- // Here, using Member, 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 MediaSourceImpl or on references to objects returned by
- // exercising this MediaSourceImpl (such as an app manipulating a SourceBuffer
- // retrieved via activeSourceBuffers()) may cause events to be dispatched by
- // these other objects.
+ // Keep the attached element (via attachment_tracer_), |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.
+ // |media_source_attachment_| and |attachment_tracer_| must be carefully set
+ // and reset: the actual derived type of the attachment (same-thread vs
+ // cross-thread, for instance) must be the same semantic as the actual derived
+ // type of the tracer. Further, if there is no attachment, then there must be
+ // no tracer that's tracking an active attachment.
+ // TODO(https://crbug.com/878133): Remove |attached_element_| once it is fully
+ // replaced by usage of |media_source_attachment_| and |attachment_tracer_|.
+ scoped_refptr<MediaSourceAttachmentSupplement> media_source_attachment_;
+ Member<MediaSourceTracer> attachment_tracer_;
Member<HTMLMediaElement> attached_element_;
Member<SourceBufferList> source_buffers_;
Member<SourceBufferList> active_source_buffers_;
@@ -161,4 +161,4 @@ class MediaSourceImpl final : public EventTargetWithInlineData,
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_IMPL_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl b/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl
index 209dba4ddd6..abada112c04 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.idl
@@ -36,7 +36,6 @@ enum EndOfStreamError {
};
[
- ImplementedAs=MediaSourceImpl,
ActiveScriptWrappable,
Exposed(Window MediaSourceStable, DedicatedWorker MediaSourceInWorkers)
] interface MediaSource : EventTarget {
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
new file mode 100644
index 00000000000..57524ac3ced
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
@@ -0,0 +1,13 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
+
+namespace blink {
+
+MediaSourceAttachmentSupplement::MediaSourceAttachmentSupplement() = default;
+
+MediaSourceAttachmentSupplement::~MediaSourceAttachmentSupplement() = default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h
new file mode 100644
index 00000000000..5c7ff8e189a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_ATTACHMENT_SUPPLEMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_ATTACHMENT_SUPPLEMENT_H_
+
+#include "third_party/blink/renderer/core/html/media/media_source_attachment.h"
+#include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class MediaSource;
+
+// Modules-specific common extension of the core MediaSourceAttachment
+// interface. Includes extra interface methods used by concrete attachments to
+// communicate with the media element, as well as method implementations and
+// members common to all concrete attachments.
+class MediaSourceAttachmentSupplement : public MediaSourceAttachment {
+ public:
+ // Communicates a change in the media resource duration to the attached media
+ // element. In a same-thread attachment, communicates this information
+ // synchronously. In a cross-thread attachment, communicates asynchronously to
+ // the media element. Same-thread synchronous notification here is primarily
+ // to preserve compliance of API behavior when not using MSE-in-Worker
+ // (setting MediaSource.duration should be synchronously in agreement with
+ // subsequent retrieval of MediaElement.duration, all on the main thread).
+ virtual void NotifyDurationChanged(MediaSourceTracer* tracer,
+ double duration) = 0;
+
+ // Retrieves the current (or a recent) media element time. Implementations may
+ // choose to either directly, synchronously consult the attached media element
+ // (via |tracer| in a same thread implementation) or rely on a "recent"
+ // currentTime pumped by the attached element via the MediaSourceAttachment
+ // interface (in a cross-thread implementation).
+ virtual double GetRecentMediaTime(MediaSourceTracer* tracer) = 0;
+
+ // Retrieves whether or not the media element currently has an error.
+ // Implementations may choose to either directly, synchronously consult the
+ // attached media element (via |tracer| in a same thread implementation) or
+ // rely on the element to correctly pump when it has an error to this
+ // attachment (in a cross-thread implementation).
+ virtual bool GetElementError(MediaSourceTracer* tracer) = 0;
+
+ virtual void OnMediaSourceContextDestroyed() = 0;
+
+ protected:
+ MediaSourceAttachmentSupplement();
+ ~MediaSourceAttachmentSupplement() override;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSourceAttachmentSupplement);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_ATTACHMENT_SUPPLEMENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.cc
index 3a36fa528a6..2003129b0dc 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.cc
@@ -30,8 +30,10 @@
#include "third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h"
-#include "third_party/blink/renderer/modules/mediasource/media_source_impl.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/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/wtf.h"
namespace blink {
@@ -45,24 +47,28 @@ void MediaSourceRegistryImpl::Init() {
void MediaSourceRegistryImpl::RegisterURL(SecurityOrigin*,
const KURL& url,
URLRegistrable* registrable) {
- // TODO(https://crbug.com/878133): Allow dedicated workers to register
- // MediaSource objectUrls, too.
- DCHECK(IsMainThread());
+ MutexLocker lock(map_mutex_);
+
+ DCHECK(IsMainThread() ||
+ RuntimeEnabledFeatures::MediaSourceInWorkersEnabled());
+
DCHECK_EQ(&registrable->Registry(), this);
DCHECK(!url.IsEmpty()); // Caller of interface should already enforce this.
- DVLOG(1) << __func__ << " url=" << url;
+ DVLOG(1) << __func__ << " url=" << url << ", IsMainThread=" << IsMainThread();
scoped_refptr<MediaSourceAttachment> attachment =
base::AdoptRef(static_cast<MediaSourceAttachment*>(registrable));
+
media_sources_.Set(url.GetString(), std::move(attachment));
}
void MediaSourceRegistryImpl::UnregisterURL(const KURL& url) {
- DVLOG(1) << __func__ << " url=" << url;
- // TODO(https://crbug.com/878133): Allow dedicated workers to unregister
- // MediaSource objectUrls, too.
- DCHECK(IsMainThread());
+ MutexLocker lock(map_mutex_);
+
+ DVLOG(1) << __func__ << " url=" << url << ", IsMainThread=" << IsMainThread();
+ DCHECK(IsMainThread() ||
+ RuntimeEnabledFeatures::MediaSourceInWorkersEnabled());
DCHECK(!url.IsEmpty()); // Caller of interface should already enforce this.
auto iter = media_sources_.find(url.GetString());
@@ -76,6 +82,8 @@ void MediaSourceRegistryImpl::UnregisterURL(const KURL& url) {
scoped_refptr<MediaSourceAttachment> MediaSourceRegistryImpl::LookupMediaSource(
const String& url) {
+ MutexLocker lock(map_mutex_);
+
DCHECK(IsMainThread());
DCHECK(!url.IsEmpty());
return media_sources_.at(url);
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h
index 5fdefc4fb3d..384b624f66d 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h
@@ -12,18 +12,15 @@
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink {
class KURL;
// This singleton lives on the main thread. It allows registration and
-// deregistration of MediaSource objectUrls. Lookups to retrieve a reference to
-// a registered MediaSource by its objectUrl are only allowed on the main
-// thread; the only intended Lookup() caller is invoked by HTMLMediaElement's
-// MSE attachment during element load.
-// TODO(https://crbug.com/878133): Refactor this to allow registration and
-// lookup of cross-thread (worker) MediaSource objectUrls.
+// deregistration of MediaSource objectUrls from both main and dedicated worker
+// threads, internally locking to access or update |media_sources_| coherently.
class MediaSourceRegistryImpl final : public MediaSourceRegistry {
public:
// Creates the singleton instance. Must be run on the main thread (expected to
@@ -32,20 +29,29 @@ class MediaSourceRegistryImpl final : public MediaSourceRegistry {
static void Init();
// MediaSourceRegistry : URLRegistry overrides for (un)registering blob URLs
- // referring to the specified media source attachment. RegisterURL creates a
- // scoped_refptr to manage the registrable's ref-counted lifetime and puts it
- // in |media_sources_|.
- void RegisterURL(SecurityOrigin*, const KURL&, URLRegistrable*) override;
+ // referring to the specified media source attachment, potentially
+ // cross-thread. RegisterURL creates a scoped_refptr to manage the
+ // registrable's ref-counted lifetime and puts it in |media_sources_|. Can be
+ // called from either the main thread or a dedicated worker thread.
+ // Regardless, must be called on the thread which created the URLRegistrable
+ // (the MediaSourceAttachment).
+ void RegisterURL(SecurityOrigin*, const KURL&, URLRegistrable*) override
+ LOCKS_EXCLUDED(map_mutex_);
// UnregisterURL removes the corresponding scoped_refptr and KURL from
- // |media_sources_| if its KURL was there.
- void UnregisterURL(const KURL&) override;
+ // |media_sources_| if its KURL was there. Can be called from either the main
+ // thread (explicit revocation or automatic revocation on attachment success)
+ // or from a worker thread (explicit revocation on worker context or worker
+ // context destruction).
+ void UnregisterURL(const KURL&) override LOCKS_EXCLUDED(map_mutex_);
// MediaSourceRegistry override that finds |url| in |media_sources_| and
// returns the corresponding scoped_refptr if found. Otherwise, returns an
- // unset scoped_refptr. |url| must be non-empty.
+ // unset scoped_refptr. |url| must be non-empty. Even with
+ // MediaSourceInWorkers feature, this must only be called on the main thread
+ // (typically for attachment of MediaSource to an HTMLMediaElement).
scoped_refptr<MediaSourceAttachment> LookupMediaSource(
- const String& url) override;
+ const String& url) override LOCKS_EXCLUDED(map_mutex_);
private:
// Construction of this singleton informs MediaSourceAttachment of this
@@ -53,7 +59,9 @@ class MediaSourceRegistryImpl final : public MediaSourceRegistry {
// this registry like lookup, registration and unregistration.
MediaSourceRegistryImpl();
- HashMap<String, scoped_refptr<MediaSourceAttachment>> media_sources_;
+ mutable Mutex map_mutex_;
+ HashMap<String, scoped_refptr<MediaSourceAttachment>> media_sources_
+ GUARDED_BY(map_mutex_);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.h
deleted file mode 100644
index c174a6c4fe4..00000000000
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_TRACER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_TRACER_IMPL_H_
-
-#include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class HTMLMediaElement;
-class MediaSourceImpl;
-
-// Concrete MediaSourceTracer that enables an HTMLMediaElement and its attached
-// MediaSourceImpl on the same (main) thread to trace into each other. This
-// enables garbage collection to automatically detect and collect idle
-// attachments of these objects that have no other strong references.
-class MediaSourceTracerImpl final : public MediaSourceTracer {
- public:
- MediaSourceTracerImpl(HTMLMediaElement* media_element,
- MediaSourceImpl* media_source);
- ~MediaSourceTracerImpl() override = default;
-
- void Trace(Visitor* visitor) const override;
-
- private:
- Member<HTMLMediaElement> media_element_;
- Member<MediaSourceImpl> media_source_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_TRACER_IMPL_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc
new file mode 100644
index 00000000000..dfc8c94ee72
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc
@@ -0,0 +1,220 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
+#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h"
+
+namespace {
+// Downcasts |tracer| to the expected same-thread attachment's tracer type.
+// Includes a debug-mode check that the tracer matches the expected attachment
+// semantic.
+blink::SameThreadMediaSourceTracer* GetTracerImpl(
+ blink::MediaSourceTracer* tracer) {
+ DCHECK(!tracer || !tracer->IsCrossThreadForDebugging());
+ return static_cast<blink::SameThreadMediaSourceTracer*>(tracer);
+}
+
+blink::MediaSource* GetMediaSource(blink::MediaSourceTracer* tracer) {
+ return GetTracerImpl(tracer)->GetMediaSource();
+}
+
+blink::HTMLMediaElement* GetMediaElement(blink::MediaSourceTracer* tracer) {
+ return GetTracerImpl(tracer)->GetMediaElement();
+}
+
+} // namespace
+
+namespace blink {
+
+SameThreadMediaSourceAttachment::SameThreadMediaSourceAttachment(
+ MediaSource* media_source,
+ util::PassKey<URLMediaSource> /* passkey */)
+ : registered_media_source_(media_source),
+ recent_element_time_(0.0),
+ element_has_error_(false),
+ element_context_destroyed_(false),
+ media_source_context_destroyed_(false) {
+ // This kind of attachment only operates on the main thread.
+ DCHECK(IsMainThread());
+
+ DVLOG(1) << __func__ << " this=" << this << " media_source=" << media_source;
+
+ // Verify that at construction time, refcounting of this object begins at
+ // precisely 1.
+ DCHECK(HasOneRef());
+}
+
+SameThreadMediaSourceAttachment::~SameThreadMediaSourceAttachment() {
+ DVLOG(1) << __func__ << " this=" << this;
+}
+
+void SameThreadMediaSourceAttachment::NotifyDurationChanged(
+ MediaSourceTracer* tracer,
+ double duration) {
+ DVLOG(1) << __func__ << " this=" << this;
+
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ HTMLMediaElement* element = GetMediaElement(tracer);
+
+ bool request_seek = element->currentTime() > duration;
+ element->DurationChanged(duration, request_seek);
+}
+
+double SameThreadMediaSourceAttachment::GetRecentMediaTime(
+ MediaSourceTracer* tracer) {
+ DVLOG(1) << __func__ << " this=" << this;
+
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ HTMLMediaElement* element = GetMediaElement(tracer);
+ double result = element->currentTime();
+
+ DVLOG(2) << __func__ << " this=" << this
+ << " -> recent time=" << recent_element_time_
+ << ", actual currentTime=" << result;
+ return result;
+}
+
+bool SameThreadMediaSourceAttachment::GetElementError(
+ MediaSourceTracer* tracer) {
+ DVLOG(1) << __func__ << " this=" << this;
+
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ HTMLMediaElement* element = GetMediaElement(tracer);
+ bool current_element_error_state = !!element->error();
+
+ DCHECK_EQ(current_element_error_state, element_has_error_);
+
+ return current_element_error_state;
+}
+
+void SameThreadMediaSourceAttachment::Unregister() {
+ DVLOG(1) << __func__ << " this=" << this;
+
+ // The only expected caller is a MediaSourceRegistryImpl on the main thread.
+ DCHECK(IsMainThread());
+
+ // Release our strong reference to the MediaSource. Note that revokeObjectURL
+ // of the url associated with this attachment could commonly follow this path
+ // while the MediaSource (and any attachment to an HTMLMediaElement) may still
+ // be alive/active.
+ DCHECK(registered_media_source_);
+ registered_media_source_ = nullptr;
+}
+
+MediaSourceTracer*
+SameThreadMediaSourceAttachment::StartAttachingToMediaElement(
+ HTMLMediaElement* element,
+ bool* success) {
+ VerifyCalledWhileContextsAliveForDebugging();
+ DCHECK(success);
+
+ if (!registered_media_source_) {
+ *success = false;
+ return nullptr;
+ }
+
+ MediaSourceTracer* tracer =
+ registered_media_source_->StartAttachingToMediaElement(
+ WrapRefCounted(this), element);
+
+ // For this same-thread attachment start, a non-nullptr tracer indicates
+ // success here.
+ *success = !!tracer;
+ return tracer;
+}
+
+void SameThreadMediaSourceAttachment::CompleteAttachingToMediaElement(
+ MediaSourceTracer* tracer,
+ std::unique_ptr<WebMediaSource> web_media_source) {
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ GetMediaSource(tracer)->CompleteAttachingToMediaElement(
+ std::move(web_media_source));
+}
+
+void SameThreadMediaSourceAttachment::Close(MediaSourceTracer* tracer) {
+ // The media element may have already notified us that its context is
+ // destroyed, so VerifyCalledWhileContextIsAliveForDebugging() is unusable in
+ // this scope.
+
+ GetMediaSource(tracer)->Close();
+}
+
+WebTimeRanges SameThreadMediaSourceAttachment::BufferedInternal(
+ MediaSourceTracer* tracer) const {
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ return GetMediaSource(tracer)->BufferedInternal();
+}
+
+WebTimeRanges SameThreadMediaSourceAttachment::SeekableInternal(
+ MediaSourceTracer* tracer) const {
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ return GetMediaSource(tracer)->SeekableInternal();
+}
+
+void SameThreadMediaSourceAttachment::OnTrackChanged(MediaSourceTracer* tracer,
+ TrackBase* track) {
+ // In this same thread implementation, the MSE side of the attachment can loop
+ // back into this from SourceBuffer's initialization segment received
+ // algorithm notifying the element, which then calls this. Regardless, we are
+ // not called as part of execution context teardown, so verification should be
+ // stable here.
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ GetMediaSource(tracer)->OnTrackChanged(track);
+}
+
+void SameThreadMediaSourceAttachment::OnElementTimeUpdate(double time) {
+ DVLOG(3) << __func__ << " this=" << this << ", time=" << time;
+
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ recent_element_time_ = time;
+}
+
+void SameThreadMediaSourceAttachment::OnElementError() {
+ DVLOG(3) << __func__ << " this=" << this;
+
+ VerifyCalledWhileContextsAliveForDebugging();
+
+ DCHECK(!element_has_error_)
+ << "At most one transition to element error per attachment is expected";
+
+ element_has_error_ = true;
+}
+
+void SameThreadMediaSourceAttachment::OnElementContextDestroyed() {
+ DVLOG(3) << __func__ << " this=" << this;
+
+ // We should only be notified once.
+ DCHECK(!element_context_destroyed_);
+
+ element_context_destroyed_ = true;
+}
+
+void SameThreadMediaSourceAttachment::OnMediaSourceContextDestroyed() {
+ DVLOG(3) << __func__ << " this=" << this;
+
+ // We should only be notified once.
+ DCHECK(!element_context_destroyed_);
+
+ media_source_context_destroyed_ = true;
+}
+
+void SameThreadMediaSourceAttachment::
+ VerifyCalledWhileContextsAliveForDebugging() const {
+ DCHECK(!element_context_destroyed_);
+ DCHECK(!media_source_context_destroyed_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h
new file mode 100644
index 00000000000..03c2d95a8ce
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h
@@ -0,0 +1,78 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
+
+#include <memory>
+
+#include "base/util/type_safety/pass_key.h"
+#include "third_party/blink/public/platform/web_time_range.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
+#include "third_party/blink/renderer/modules/mediasource/url_media_source.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+// Concrete attachment that supports operation only on the main thread.
+class SameThreadMediaSourceAttachment final
+ : public MediaSourceAttachmentSupplement {
+ public:
+ // The only intended caller of this constructor is
+ // URLMediaSource::createObjectUrl, made more clear by using the PassKey. The
+ // raw pointer is then adopted into a scoped_refptr in
+ // MediaSourceRegistryImpl::RegisterURL.
+ SameThreadMediaSourceAttachment(MediaSource* media_source,
+ util::PassKey<URLMediaSource>);
+
+ // MediaSourceAttachmentSupplement
+ void NotifyDurationChanged(MediaSourceTracer* tracer, double duration) final;
+ double GetRecentMediaTime(MediaSourceTracer* tracer) final;
+ bool GetElementError(MediaSourceTracer* tracer) final;
+ void OnMediaSourceContextDestroyed() final;
+
+ // MediaSourceAttachment
+ void Unregister() final;
+ MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*,
+ bool* success) final;
+ void CompleteAttachingToMediaElement(MediaSourceTracer* tracer,
+ std::unique_ptr<WebMediaSource>) final;
+
+ void Close(MediaSourceTracer* tracer) final;
+ WebTimeRanges BufferedInternal(MediaSourceTracer* tracer) const final;
+ WebTimeRanges SeekableInternal(MediaSourceTracer* tracer) const final;
+ void OnTrackChanged(MediaSourceTracer* tracer, TrackBase*) final;
+
+ void OnElementTimeUpdate(double time) final;
+ void OnElementError() final;
+ void OnElementContextDestroyed() final;
+
+ private:
+ ~SameThreadMediaSourceAttachment() override;
+
+ // In this same thread implementation, if the media element context is
+ // destroyed, then so should be the Media Source's context. This method
+ // this precondition in debug mode.
+ void VerifyCalledWhileContextsAliveForDebugging() const;
+
+ // Cache of the registered MediaSource. Retains strong reference from
+ // construction of this object until Unregister() is called.
+ Persistent<MediaSource> registered_media_source_;
+
+ // These are mostly used to verify correct behavior of the media element and
+ // media source state pumping in debug builds. In a cross-thread attachment
+ // implementation, state like this will be relied upon for servicing the
+ // MediaSource API.
+ double recent_element_time_; // See OnElementTimeUpdate().
+ bool element_has_error_; // See OnElementError().
+ bool element_context_destroyed_; // See OnElementContextDestroyed().
+ bool media_source_context_destroyed_; // See OnMediaSourceContextDestroyed().
+
+ DISALLOW_COPY_AND_ASSIGN(SameThreadMediaSourceAttachment);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.cc b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.cc
index f2db6cae0b4..20a435ed77e 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_tracer_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.cc
@@ -2,18 +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/modules/mediasource/media_source_tracer_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
-#include "third_party/blink/renderer/modules/mediasource/media_source_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
namespace blink {
-MediaSourceTracerImpl::MediaSourceTracerImpl(HTMLMediaElement* media_element,
- MediaSourceImpl* media_source)
+SameThreadMediaSourceTracer::SameThreadMediaSourceTracer(
+ HTMLMediaElement* media_element,
+ MediaSource* media_source)
: media_element_(media_element), media_source_(media_source) {}
-void MediaSourceTracerImpl::Trace(Visitor* visitor) const {
+void SameThreadMediaSourceTracer::Trace(Visitor* visitor) const {
visitor->Trace(media_element_);
visitor->Trace(media_source_);
MediaSourceTracer::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h
new file mode 100644
index 00000000000..d65ff6c1a9d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/mediasource/same_thread_media_source_tracer.h
@@ -0,0 +1,43 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_TRACER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_TRACER_H_
+
+#include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class HTMLMediaElement;
+class MediaSource;
+
+// Concrete MediaSourceTracer that enables an HTMLMediaElement and its attached
+// MediaSource on the same (main) thread to trace into each other. This enables
+// garbage collection to automatically detect and collect idle attachments of
+// these objects that have no other strong references. Concrete
+// MediaSourceAttachments use SameThreadMediaSourceTracers as the authoritative
+// reference holders for each side of the attachments.
+class SameThreadMediaSourceTracer final : public MediaSourceTracer {
+ public:
+ SameThreadMediaSourceTracer(HTMLMediaElement* media_element,
+ MediaSource* media_source);
+ ~SameThreadMediaSourceTracer() override = default;
+
+ void Trace(Visitor* visitor) const override;
+
+ bool IsCrossThreadForDebugging() const override { return false; }
+
+ HTMLMediaElement* GetMediaElement() { return media_element_; }
+
+ MediaSource* GetMediaSource() { return media_source_; }
+
+ private:
+ Member<HTMLMediaElement> media_element_;
+ Member<MediaSource> media_source_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_TRACER_H_
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 2aeec55aad2..eb9958e7f29 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -50,7 +50,7 @@
#include "third_party/blink/renderer/core/html/track/video_track_list.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
-#include "third_party/blink/renderer/modules/mediasource/media_source_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
#include "third_party/blink/renderer/modules/mediasource/source_buffer_track_base_supplement.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -72,13 +72,13 @@ static bool ThrowExceptionIfRemovedOrUpdating(bool is_removed,
bool is_updating,
ExceptionState& exception_state) {
if (is_removed) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"This SourceBuffer has been removed from the parent media source.");
return true;
}
if (is_updating) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"This SourceBuffer is still processing an 'appendBuffer' or "
"'remove' operation.");
@@ -105,7 +105,7 @@ WTF::String WebTimeRangesToString(const WebTimeRanges& ranges) {
} // namespace
SourceBuffer::SourceBuffer(std::unique_ptr<WebSourceBuffer> web_source_buffer,
- MediaSourceImpl* source,
+ MediaSource* source,
EventQueue* async_event_queue)
: ExecutionContextLifecycleObserver(source->GetExecutionContext()),
web_source_buffer_(std::move(web_source_buffer)),
@@ -126,6 +126,9 @@ SourceBuffer::SourceBuffer(std::unique_ptr<WebSourceBuffer> web_source_buffer,
DCHECK(web_source_buffer_);
DCHECK(source_);
DCHECK(source_->MediaElement());
+ // TODO(https://crbug.com/878133): Enable construction of media tracks that
+ // don't reference the media element if, for instance, they are owned by a
+ // different execution context.
audio_tracks_ =
MakeGarbageCollected<AudioTrackList>(*source_->MediaElement());
video_tracks_ =
@@ -143,14 +146,12 @@ void SourceBuffer::Dispose() {
web_source_buffer_.reset();
}
-const AtomicString& SourceBuffer::SegmentsKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, segments, ("segments"));
- return segments;
+AtomicString SourceBuffer::SegmentsKeyword() {
+ return "segments";
}
-const AtomicString& SourceBuffer::SequenceKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, sequence, ("sequence"));
- return sequence;
+AtomicString SourceBuffer::SequenceKeyword() {
+ return "sequence";
}
void SourceBuffer::setMode(const AtomicString& new_mode,
@@ -173,7 +174,7 @@ void SourceBuffer::setMode(const AtomicString& new_mode,
// then throw a TypeError exception and abort these steps.
if (web_source_buffer_->GetGenerateTimestampsFlag() &&
new_mode == SegmentsKeyword()) {
- MediaSourceImpl::LogAndThrowTypeError(
+ MediaSource::LogAndThrowTypeError(
exception_state, "The mode value provided (" + SegmentsKeyword() +
") is invalid for a byte stream format that uses "
"generated timestamps.");
@@ -196,7 +197,7 @@ void SourceBuffer::setMode(const AtomicString& new_mode,
if (new_mode == SequenceKeyword())
append_mode = WebSourceBuffer::kAppendModeSequence;
if (!web_source_buffer_->SetMode(append_mode)) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The mode may not be set while the SourceBuffer's append state is "
"'PARSING_MEDIA_SEGMENT'.");
@@ -213,7 +214,7 @@ TimeRanges* SourceBuffer::buffered(ExceptionState& exception_state) const {
// parent media source then throw an InvalidStateError exception and abort
// these steps.
if (IsRemoved()) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"This SourceBuffer has been removed from the parent media source.");
return nullptr;
@@ -260,7 +261,7 @@ void SourceBuffer::setTimestampOffset(double offset,
// 6. If the mode attribute equals "sequence", then set the group start
// timestamp to new timestamp offset.
if (!web_source_buffer_->SetTimestampOffset(offset)) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The timestamp offset may not be set while the SourceBuffer's append "
"state is 'PARSING_MEDIA_SEGMENT'.");
@@ -302,7 +303,7 @@ void SourceBuffer::setAppendWindowStart(double start,
// 3. If the new value is less than 0 or greater than or equal to
// appendWindowEnd then throw a TypeError exception and abort these steps.
if (start < 0 || start >= append_window_end_) {
- MediaSourceImpl::LogAndThrowTypeError(
+ MediaSource::LogAndThrowTypeError(
exception_state,
ExceptionMessages::IndexOutsideRange(
"value", start, 0.0, ExceptionMessages::kExclusiveBound,
@@ -337,14 +338,14 @@ void SourceBuffer::setAppendWindowEnd(double end,
// 3. If the new value equals NaN, then throw a TypeError and abort these
// steps.
if (std::isnan(end)) {
- MediaSourceImpl::LogAndThrowTypeError(
- exception_state, ExceptionMessages::NotAFiniteNumber(end));
+ MediaSource::LogAndThrowTypeError(exception_state,
+ ExceptionMessages::NotAFiniteNumber(end));
return;
}
// 4. If the new value is less than or equal to appendWindowStart then throw a
// TypeError exception and abort these steps.
if (end <= append_window_start_) {
- MediaSourceImpl::LogAndThrowTypeError(
+ MediaSource::LogAndThrowTypeError(
exception_state, ExceptionMessages::IndexExceedsMinimumBound(
"value", end, append_window_start_));
return;
@@ -390,13 +391,13 @@ void SourceBuffer::abort(ExceptionState& exception_state) {
// "open" state then throw an InvalidStateError exception and abort these
// steps.
if (IsRemoved()) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"This SourceBuffer has been removed from the parent media source.");
return;
}
if (!source_->IsOpen()) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The parent media source's readyState is not 'open'.");
return;
@@ -410,15 +411,14 @@ void SourceBuffer::abort(ExceptionState& exception_state) {
// is implemented behind the MediaSourceNewAbortAndDuration
// RuntimeEnabledFeature.
if (RuntimeEnabledFeatures::MediaSourceNewAbortAndDurationEnabled()) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"Aborting asynchronous remove() operation is disallowed.");
return;
}
- Deprecation::CountDeprecation(
- source_->MediaElement()->GetExecutionContext(),
- WebFeature::kMediaSourceAbortRemove);
+ Deprecation::CountDeprecation(GetExecutionContext(),
+ WebFeature::kMediaSourceAbortRemove);
CancelRemove();
}
@@ -459,7 +459,7 @@ void SourceBuffer::remove(double start,
// exception and abort these steps.
if (start < 0 || std::isnan(source_->duration()) ||
start > source_->duration()) {
- MediaSourceImpl::LogAndThrowTypeError(
+ MediaSource::LogAndThrowTypeError(
exception_state,
ExceptionMessages::IndexOutsideRange(
"start", start, 0.0, ExceptionMessages::kExclusiveBound,
@@ -471,7 +471,7 @@ void SourceBuffer::remove(double start,
// 5. If end is less than or equal to start or end equals NaN, then throw a
// TypeError exception and abort these steps.
if (end <= start || std::isnan(end)) {
- MediaSourceImpl::LogAndThrowTypeError(
+ MediaSource::LogAndThrowTypeError(
exception_state,
"The end value provided (" + String::Number(end) +
") must be greater than the start value provided (" +
@@ -517,8 +517,8 @@ void SourceBuffer::changeType(const String& type,
// 1. If type is an empty string then throw a TypeError exception and abort
// these steps.
if (type.IsEmpty()) {
- MediaSourceImpl::LogAndThrowTypeError(exception_state,
- "The type provided is empty");
+ MediaSource::LogAndThrowTypeError(exception_state,
+ "The type provided is empty");
return;
}
@@ -542,9 +542,9 @@ void SourceBuffer::changeType(const String& type,
// here. As part of that, CanChangeType in Chromium should inherit relaxation
// of impl's StreamParserFactory (since it returns true iff a stream parser
// can be constructed with |type|). See https://crbug.com/535738.
- if (!MediaSourceImpl::isTypeSupported(GetExecutionContext(), type) ||
+ if (!MediaSource::isTypeSupported(GetExecutionContext(), type) ||
!web_source_buffer_->CanChangeType(content_type.GetType(), codecs)) {
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kNotSupportedError,
"Changing to the type provided ('" + type + "') is not supported.");
return;
@@ -771,8 +771,13 @@ void SourceBuffer::RemoveMediaTracks() {
double SourceBuffer::GetMediaTime() {
double media_time = std::numeric_limits<float>::quiet_NaN();
- if (source_ && source_->MediaElement())
- media_time = source_->MediaElement()->currentTime();
+ if (source_) {
+ scoped_refptr<MediaSourceAttachmentSupplement> attachment;
+ MediaSourceTracer* tracer;
+ std::tie(attachment, tracer) = source_->AttachmentAndTracer();
+ if (attachment)
+ media_time = attachment->GetRecentMediaTime(tracer);
+ }
return media_time;
}
@@ -1131,7 +1136,7 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
// TODO(wolenetz): Use the data to scope additional work. See
// https://crbug.com/739931.
UseCounter::Count(
- source_->MediaElement()->GetDocument(),
+ GetExecutionContext(),
WebFeature::kMediaSourceKeyframeTimeGreaterThanDependant);
break;
case WebSourceBufferClient::kMuxedSequenceMode:
@@ -1140,7 +1145,7 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
// SourceBuffer, at Media.OriginUrl.MSE.MuxedSequenceModeSourceBuffer.
// TODO(wolenetz): Use the data to scope additional work. See
// https://crbug.com/737757.
- UseCounter::Count(source_->MediaElement()->GetDocument(),
+ UseCounter::Count(GetExecutionContext(),
WebFeature::kMediaSourceMuxedSequenceMode);
break;
case WebSourceBufferClient::kGroupEndTimestampDecreaseWithinMediaSegment:
@@ -1150,7 +1155,7 @@ void SourceBuffer::NotifyParseWarning(const ParseWarning warning) {
// https://crbug.com/920853 and
// https://github.com/w3c/media-source/issues/203.
UseCounter::Count(
- source_->MediaElement()->GetDocument(),
+ GetExecutionContext(),
WebFeature::kMediaSourceGroupEndTimestampDecreaseWithinMediaSegment);
break;
}
@@ -1211,9 +1216,13 @@ bool SourceBuffer::PrepareAppend(double media_time,
// 3. If the HTMLMediaElement.error attribute is not null, then throw an
// InvalidStateError exception and abort these steps.
DCHECK(source_);
- DCHECK(source_->MediaElement());
- if (source_->MediaElement()->error()) {
- MediaSourceImpl::LogAndThrowDOMException(
+ scoped_refptr<MediaSourceAttachmentSupplement> attachment;
+ MediaSourceTracer* tracer;
+ std::tie(attachment, tracer) = source_->AttachmentAndTracer();
+ DCHECK(attachment);
+ DCHECK(tracer);
+ if (attachment->GetElementError(tracer)) {
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kInvalidStateError,
"The HTMLMediaElement.error attribute is not null.");
TRACE_EVENT_NESTABLE_ASYNC_END0("media", "SourceBuffer::prepareAppend",
@@ -1236,7 +1245,7 @@ bool SourceBuffer::PrepareAppend(double media_time,
// If the incoming data exceeds wtf_size_t::max, then our implementation
// cannot deal with it, so we also throw a QuotaExceededError.
DVLOG(3) << __func__ << " this=" << this << " -> throw QuotaExceededError";
- MediaSourceImpl::LogAndThrowDOMException(
+ MediaSource::LogAndThrowDOMException(
exception_state, DOMExceptionCode::kQuotaExceededError,
"The SourceBuffer is full, and cannot free space to append additional "
"buffers.");
@@ -1254,11 +1263,9 @@ bool SourceBuffer::EvictCodedFrames(double media_time, size_t new_data_size) {
DCHECK(source_);
DCHECK(source_->MediaElement());
- // Nothing to do if the mediaElement does not yet have frames to evict.
- if (source_->MediaElement()->getReadyState() <
- HTMLMediaElement::kHaveMetadata) {
+ // Nothing to do if this SourceBuffer does not yet have frames to evict.
+ if (!first_initialization_segment_received_)
return true;
- }
bool result = web_source_buffer_->EvictCodedFrames(media_time, new_data_size);
if (!result) {
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 721d1dcb39b..d6277c60778 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.h
@@ -49,7 +49,7 @@ class DOMArrayBuffer;
class DOMArrayBufferView;
class EventQueue;
class ExceptionState;
-class MediaSourceImpl;
+class MediaSource;
class TimeRanges;
class VideoTrackList;
class WebSourceBuffer;
@@ -62,10 +62,10 @@ class SourceBuffer final : public EventTargetWithInlineData,
USING_PRE_FINALIZER(SourceBuffer, Dispose);
public:
- static const AtomicString& SegmentsKeyword();
- static const AtomicString& SequenceKeyword();
+ static AtomicString SegmentsKeyword();
+ static AtomicString SequenceKeyword();
- SourceBuffer(std::unique_ptr<WebSourceBuffer>, MediaSourceImpl*, EventQueue*);
+ SourceBuffer(std::unique_ptr<WebSourceBuffer>, MediaSource*, EventQueue*);
~SourceBuffer() override;
// SourceBuffer.idl methods
@@ -160,7 +160,7 @@ class SourceBuffer final : public EventTargetWithInlineData,
// 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.
- Member<MediaSourceImpl> source_;
+ Member<MediaSource> source_;
Member<TrackDefaultList> track_defaults_;
Member<EventQueue> async_event_queue_;
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/track_default.cc b/chromium/third_party/blink/renderer/modules/mediasource/track_default.cc
index c9373a99ad3..53a2352a698 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/track_default.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/track_default.cc
@@ -13,19 +13,16 @@
namespace blink {
-const AtomicString& TrackDefault::AudioKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, audio, ("audio"));
- return audio;
+AtomicString TrackDefault::AudioKeyword() {
+ return "audio";
}
-const AtomicString& TrackDefault::VideoKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, video, ("video"));
- return video;
+AtomicString TrackDefault::VideoKeyword() {
+ return "video";
}
-const AtomicString& TrackDefault::TextKeyword() {
- DEFINE_STATIC_LOCAL(const AtomicString, text, ("text"));
- return text;
+AtomicString TrackDefault::TextKeyword() {
+ return "text";
}
ScriptValue TrackDefault::kinds(ScriptState* script_state) const {
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/track_default.h b/chromium/third_party/blink/renderer/modules/mediasource/track_default.h
index fd68ef348aa..fd170f981d5 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/track_default.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/track_default.h
@@ -18,9 +18,9 @@ class TrackDefault final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static const AtomicString& AudioKeyword();
- static const AtomicString& VideoKeyword();
- static const AtomicString& TextKeyword();
+ static AtomicString AudioKeyword();
+ static AtomicString VideoKeyword();
+ static AtomicString TextKeyword();
static TrackDefault* Create(const AtomicString& type,
const String& language,
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.cc b/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.cc
index 0193c7b3d64..9a1acacc5d5 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.cc
+++ b/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.cc
@@ -34,33 +34,50 @@
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/media/media_source_attachment.h"
#include "third_party/blink/renderer/core/url/dom_url.h"
-#include "third_party/blink/renderer/modules/mediasource/media_source_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.h"
+#include "third_party/blink/renderer/modules/mediasource/media_source.h"
#include "third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h"
+#include "third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
// static
String URLMediaSource::createObjectURL(ScriptState* script_state,
- MediaSourceImpl* source) {
- // Since WebWorkers cannot obtain MediaSource objects (yet), we should be on
- // the main thread.
- // TODO(https://crbug.com/878133): Let DedicatedWorkers create MediaSource
- // object URLs.
- DCHECK(IsMainThread());
+ MediaSource* source) {
+ // Since WebWorkers previously could not obtain MediaSource objects, we should
+ // be on the main thread unless MediaSourceInWorkers is enabled and we're in a
+ // dedicated worker execution context.
+ DCHECK(IsMainThread() ||
+ RuntimeEnabledFeatures::MediaSourceInWorkersEnabled());
ExecutionContext* execution_context = ExecutionContext::From(script_state);
DCHECK(execution_context);
DCHECK(source);
+ MediaSourceAttachment* attachment;
+ if (execution_context->IsDedicatedWorkerGlobalScope()) {
+ DCHECK(!IsMainThread());
+
+ // PassKey usage here ensures that only we can call the constructor.
+ attachment = new CrossThreadMediaSourceAttachment(source, PassKey());
+ } else {
+ // Other contexts outside of main window thread or conditionally a dedicated
+ // worker thread are not supported (like Shared Worker and Service Worker).
+ DCHECK(IsMainThread() && execution_context->IsWindow());
+
+ // PassKey usage here ensures that only we can call the constructor.
+ attachment = new SameThreadMediaSourceAttachment(source, PassKey());
+ }
+
UseCounter::Count(execution_context, WebFeature::kCreateObjectURLMediaSource);
- // This creation of a ThreadSafeRefCounted object should have a refcount of 1
- // immediately. It will be adopted into a scoped_refptr in
- // MediaSourceRegistryImpl::RegisterURL. See also MediaSourceAttachment (and
- // usage in HTMLMediaElement, MediaSourceRegistry{Impl}, and
- // MediaSource{Impl}) for further detail.
- MediaSourceAttachment* attachment = new MediaSourceAttachment(source);
+ // The creation of a ThreadSafeRefCounted attachment object, above, should
+ // have a refcount of 1 immediately. It will be adopted into a scoped_refptr
+ // in MediaSourceRegistryImpl::RegisterURL. See also MediaSourceAttachment
+ // (and usage in HTMLMediaElement, MediaSourceRegistry{Impl}, and MediaSource)
+ // for further detail.
DCHECK(attachment->HasOneRef());
String url = DOMURL::CreatePublicURL(execution_context, attachment);
diff --git a/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h b/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h
index 2f2258853c2..4510b38268c 100644
--- a/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h
+++ b/chromium/third_party/blink/renderer/modules/mediasource/url_media_source.h
@@ -31,19 +31,21 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_URL_MEDIA_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_URL_MEDIA_SOURCE_H_
+#include "base/util/type_safety/pass_key.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
-class MediaSourceImpl;
+class MediaSource;
class ScriptState;
class URLMediaSource {
STATIC_ONLY(URLMediaSource);
public:
- static String createObjectURL(ScriptState*, MediaSourceImpl*);
+ using PassKey = util::PassKey<URLMediaSource>;
+ static String createObjectURL(ScriptState*, MediaSource*);
};
} // 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 a5d6e7a5240..11b02076b1c 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -11,7 +11,6 @@ blink_modules_sources("mediastream") {
"apply_constraints_request.cc",
"apply_constraints_request.h",
"dom_window_media_stream.h",
- "encoded_frame.h",
"input_device_info.cc",
"input_device_info.h",
"local_media_stream_audio_source.cc",
@@ -97,7 +96,15 @@ blink_modules_sources("mediastream") {
"//build:chromecast_buildflags",
"//media/capture/mojom:image_capture_blink",
"//media/webrtc",
+ "//services/viz/public/cpp/gpu:gpu",
+ "//third_party/blink/renderer/modules/imagecapture:imagecapture",
+ "//third_party/blink/renderer/modules/peerconnection:peerconnection",
+ "//third_party/libyuv:libyuv",
]
+ allow_circular_includes_from =
+ [ "//third_party/blink/renderer/modules/imagecapture:imagecapture" ]
+
+ public_deps = [ "//media/capture:capture_lib" ]
}
source_set("test_support") {
@@ -124,8 +131,11 @@ source_set("test_support") {
"//testing/gmock",
"//third_party/blink/public:test_headers",
"//third_party/blink/public/mojom:mojom_platform_blink_headers",
+ "//third_party/blink/renderer/modules:modules",
"//third_party/webrtc_overrides:webrtc_component",
]
+ public_deps = [ "//third_party/blink/renderer/platform:test_support" ]
+
configs += [ "//third_party/blink/renderer:inside_blink" ]
}
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 68c45c08f75..4958db291d8 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -8,6 +8,9 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/public/platform/task_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"
@@ -27,6 +30,7 @@
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/mediastream/webrtc_uma_histograms.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -253,6 +257,32 @@ void MediaDevices::StopObserving() {
receiver_.reset();
}
+namespace {
+
+void RecordEnumeratedDevices(ScriptPromiseResolver* resolver,
+ const MediaDeviceInfoVector& media_devices) {
+ if (!IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+ WebFeature::kMediaDevicesEnumerateDevices)) {
+ return;
+ }
+ Document* document = LocalDOMWindow::From(resolver->GetScriptState())
+ ->GetFrame()
+ ->GetDocument();
+ IdentifiableTokenBuilder builder;
+ for (const auto& device_info : media_devices) {
+ builder.AddToken(IdentifiabilityBenignStringToken(device_info->deviceId()));
+ builder.AddToken(IdentifiabilityBenignStringToken(device_info->kind()));
+ builder.AddToken(IdentifiabilityBenignStringToken(device_info->label()));
+ builder.AddToken(IdentifiabilityBenignStringToken(device_info->groupId()));
+ }
+ IdentifiabilityMetricBuilder(document->UkmSourceID())
+ .SetWebfeature(WebFeature::kMediaDevicesEnumerateDevices,
+ builder.GetToken())
+ .Record(document->UkmRecorder());
+}
+
+} // namespace
+
void MediaDevices::DevicesEnumerated(
ScriptPromiseResolver* resolver,
const Vector<Vector<WebMediaDeviceInfo>>& enumeration,
@@ -323,6 +353,8 @@ void MediaDevices::DevicesEnumerated(
}
}
+ RecordEnumeratedDevices(resolver, media_devices);
+
if (enumerate_devices_test_callback_)
std::move(enumerate_devices_test_callback_).Run(media_devices);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc
index f73c1d142d4..a47adc88820 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc
@@ -427,17 +427,19 @@ const AtomicString& MediaStream::InterfaceName() const {
}
void MediaStream::AddTrackByComponentAndFireEvents(
- MediaStreamComponent* component) {
+ MediaStreamComponent* component,
+ DispatchEventTiming event_timing) {
DCHECK(component);
if (!GetExecutionContext())
return;
auto* track =
MakeGarbageCollected<MediaStreamTrack>(GetExecutionContext(), component);
- AddTrackAndFireEvents(track);
+ AddTrackAndFireEvents(track, event_timing);
}
void MediaStream::RemoveTrackByComponentAndFireEvents(
- MediaStreamComponent* component) {
+ MediaStreamComponent* component,
+ DispatchEventTiming event_timing) {
DCHECK(component);
if (!GetExecutionContext())
return;
@@ -467,16 +469,29 @@ void MediaStream::RemoveTrackByComponentAndFireEvents(
MediaStreamTrack* track = (*tracks)[index];
track->UnregisterMediaStream(this);
tracks->EraseAt(index);
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamTrackEvent>(
- event_type_names::kRemovetrack, track));
+ bool became_inactive = false;
if (active() && EmptyOrOnlyEndedTracks()) {
descriptor_->SetActive(false);
- ScheduleDispatchEvent(Event::Create(event_type_names::kInactive));
+ became_inactive = true;
+ }
+
+ // Fire events synchronously or asynchronously.
+ if (event_timing == DispatchEventTiming::kImmediately) {
+ DispatchEvent(*MakeGarbageCollected<MediaStreamTrackEvent>(
+ event_type_names::kRemovetrack, track));
+ if (became_inactive)
+ DispatchEvent(*Event::Create(event_type_names::kInactive));
+ } else {
+ ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamTrackEvent>(
+ event_type_names::kRemovetrack, track));
+ if (became_inactive)
+ ScheduleDispatchEvent(Event::Create(event_type_names::kInactive));
}
}
-void MediaStream::AddTrackAndFireEvents(MediaStreamTrack* track) {
+void MediaStream::AddTrackAndFireEvents(MediaStreamTrack* track,
+ DispatchEventTiming event_timing) {
DCHECK(track);
switch (track->Component()->Source()->GetType()) {
case MediaStreamSource::kTypeAudio:
@@ -489,18 +504,30 @@ void MediaStream::AddTrackAndFireEvents(MediaStreamTrack* track) {
track->RegisterMediaStream(this);
descriptor_->AddComponent(track->Component());
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamTrackEvent>(
- event_type_names::kAddtrack, track));
-
+ bool became_active = false;
if (!active() && !track->Ended()) {
descriptor_->SetActive(true);
- ScheduleDispatchEvent(Event::Create(event_type_names::kActive));
+ became_active = true;
+ }
+
+ // Fire events synchronously or asynchronously.
+ if (event_timing == DispatchEventTiming::kImmediately) {
+ DispatchEvent(*MakeGarbageCollected<MediaStreamTrackEvent>(
+ event_type_names::kAddtrack, track));
+ if (became_active)
+ DispatchEvent(*Event::Create(event_type_names::kActive));
+ } else {
+ ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamTrackEvent>(
+ event_type_names::kAddtrack, track));
+ if (became_active)
+ ScheduleDispatchEvent(Event::Create(event_type_names::kActive));
}
}
-void MediaStream::RemoveTrackAndFireEvents(MediaStreamTrack* track) {
+void MediaStream::RemoveTrackAndFireEvents(MediaStreamTrack* track,
+ DispatchEventTiming event_timing) {
DCHECK(track);
- RemoveTrackByComponentAndFireEvents(track->Component());
+ RemoveTrackByComponentAndFireEvents(track->Component(), event_timing);
}
void MediaStream::ScheduleDispatchEvent(Event* event) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h
index 2fda857a970..d2d601eaf2f 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.h
@@ -126,13 +126,15 @@ class MODULES_EXPORT MediaStream final
// MediaStreamDescriptorClient implementation
void StreamEnded() override;
- void AddTrackByComponentAndFireEvents(MediaStreamComponent*) override;
- void RemoveTrackByComponentAndFireEvents(MediaStreamComponent*) override;
+ void AddTrackByComponentAndFireEvents(MediaStreamComponent*,
+ DispatchEventTiming) override;
+ void RemoveTrackByComponentAndFireEvents(MediaStreamComponent*,
+ DispatchEventTiming) override;
// Adds the track and, unlike JavaScript-invoked addTrack(), fires related
- // events like "onaddtrack".
- void AddTrackAndFireEvents(MediaStreamTrack*);
- void RemoveTrackAndFireEvents(MediaStreamTrack*);
+ // events like "onaddtrack" either synchronously or in a scheduled event.
+ void AddTrackAndFireEvents(MediaStreamTrack*, DispatchEventTiming);
+ void RemoveTrackAndFireEvents(MediaStreamTrack*, DispatchEventTiming);
void AddRemoteTrack(MediaStreamTrack*);
void RemoveRemoteTrack(MediaStreamTrack*);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
index 04477de4d06..868b1729ac0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
@@ -67,6 +67,11 @@ bool UseMultiChannelCaptureProcessing() {
features::kWebRtcEnableCaptureMultiChannelApm);
}
+bool Allow48kHzApmProcessing() {
+ return base::FeatureList::IsEnabled(
+ features::kWebRtcAllow48kHzProcessingOnArm);
+}
+
constexpr int kAudioProcessingNumberOfChannels = 1;
constexpr int kBuffersPerSecond = 100; // 10 ms per buffer.
@@ -576,24 +581,43 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
if (properties.goog_auto_gain_control ||
properties.goog_experimental_auto_gain_control) {
- bool use_hybrid_agc = false;
- base::Optional<bool> use_peaks_not_rms;
- base::Optional<int> saturation_margin;
- if (properties.goog_experimental_auto_gain_control) {
- use_hybrid_agc = base::FeatureList::IsEnabled(features::kWebRtcHybridAgc);
- if (use_hybrid_agc) {
- DCHECK(properties.goog_auto_gain_control)
- << "Cannot enable hybrid AGC when AGC is disabled.";
- }
- use_peaks_not_rms = base::GetFieldTrialParamByFeatureAsBool(
- features::kWebRtcHybridAgc, "use_peaks_not_rms", false);
- saturation_margin = base::GetFieldTrialParamByFeatureAsInt(
- features::kWebRtcHybridAgc, "saturation_margin", -1);
+ base::Optional<blink::AdaptiveGainController2Properties> agc2_properties;
+ if (properties.goog_experimental_auto_gain_control &&
+ base::FeatureList::IsEnabled(features::kWebRtcHybridAgc)) {
+ DCHECK(properties.goog_auto_gain_control)
+ << "Cannot enable hybrid AGC when AGC is disabled.";
+ agc2_properties = blink::AdaptiveGainController2Properties{};
+ agc2_properties->vad_probability_attack =
+ base::GetFieldTrialParamByFeatureAsDouble(
+ features::kWebRtcHybridAgc, "vad_probability_attack", 1.0);
+ agc2_properties->use_peaks_not_rms =
+ base::GetFieldTrialParamByFeatureAsBool(features::kWebRtcHybridAgc,
+ "use_peaks_not_rms", false);
+ agc2_properties->level_estimator_speech_frames_threshold =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kWebRtcHybridAgc,
+ "level_estimator_speech_frames_threshold", 1);
+ agc2_properties->initial_saturation_margin_db =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kWebRtcHybridAgc, "initial_saturation_margin", 20);
+ agc2_properties->extra_saturation_margin_db =
+ base::GetFieldTrialParamByFeatureAsInt(features::kWebRtcHybridAgc,
+ "extra_saturation_margin", 5);
+ agc2_properties->gain_applier_speech_frames_threshold =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kWebRtcHybridAgc,
+ "gain_applier_speech_frames_threshold", 1);
+ agc2_properties->max_gain_change_db_per_second =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kWebRtcHybridAgc, "max_gain_change_db_per_second", 3);
+ agc2_properties->max_output_noise_level_dbfs =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kWebRtcHybridAgc, "max_output_noise_level_dbfs", -50);
}
blink::ConfigAutomaticGainControl(
- &apm_config, properties.goog_auto_gain_control,
- properties.goog_experimental_auto_gain_control, use_hybrid_agc,
- use_peaks_not_rms, saturation_margin, gain_control_compression_gain_db);
+ properties.goog_auto_gain_control,
+ properties.goog_experimental_auto_gain_control, agc2_properties,
+ gain_control_compression_gain_db, apm_config);
}
if (goog_typing_detection) {
@@ -603,6 +627,12 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
blink::EnableTypingDetection(&apm_config, typing_detector_.get());
}
+ // Ensure that 48 kHz APM processing is always active. This overrules the
+ // default setting in WebRTC of 32 kHz for ARM platforms.
+ if (Allow48kHzApmProcessing()) {
+ apm_config.pipeline.maximum_internal_processing_rate = 48000;
+ }
+
apm_config.residual_echo_detector.enabled = false;
audio_processing_->ApplyConfig(apm_config);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
index 9a7248aa983..9f300df6d9f 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
@@ -249,10 +249,6 @@ VideoTrackAdapterSettings SelectVideoTrackAdapterSettings(
if (frame_rate_set.Max() && track_max_frame_rate > *frame_rate_set.Max())
track_max_frame_rate = *frame_rate_set.Max();
}
- // Disable frame-rate adjustment if the requested rate is greater than the
- // source rate.
- if (track_max_frame_rate >= source_format.frame_rate)
- track_max_frame_rate = 0.0;
return VideoTrackAdapterSettings(target_resolution, track_min_aspect_ratio,
track_max_aspect_ratio,
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_test.cc
index 9bc18d3006c..419d68170aa 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_test.cc
@@ -544,9 +544,7 @@ TEST_F(MediaStreamConstraintsUtilTest, VideoTrackAdapterSettingsConstrained) {
EXPECT_EQ(kSourceWidth, result.target_width());
EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
EXPECT_EQ(kMaxAspectRatio, result.max_aspect_ratio());
- // No frame-rate adjustment because the track will use the same frame rate
- // as the source.
- EXPECT_EQ(0.0, result.max_frame_rate());
+ EXPECT_EQ(kSourceFrameRate, result.max_frame_rate());
}
// High frame rate.
@@ -563,9 +561,7 @@ TEST_F(MediaStreamConstraintsUtilTest, VideoTrackAdapterSettingsConstrained) {
EXPECT_EQ(kSourceWidth, result.target_width());
EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
EXPECT_EQ(kMaxAspectRatio, result.max_aspect_ratio());
- // No frame-rate adjustment because the track will use a frame rate that is
- // greater than the source's.
- EXPECT_EQ(0.0, result.max_frame_rate());
+ EXPECT_EQ(kHighFrameRate, result.max_frame_rate());
}
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_content_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_content_test.cc
index 10935eea372..8c2508628f6 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_content_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_content_test.cc
@@ -40,24 +40,26 @@ void CheckNonFrameRateDefaults(const VideoCaptureSettings& result) {
EXPECT_EQ(std::string(), result.device_id());
}
-void CheckTrackAdapterSettingsEqualsFormat(const VideoCaptureSettings& result) {
+void CheckTrackAdapterSettingsEqualsFormat(const VideoCaptureSettings& result,
+ double frame_rate = 0.0) {
// For content capture, resolution and frame rate should always be the same
// for source and track.
EXPECT_TRUE(result.track_adapter_settings().target_size().has_value());
EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width());
EXPECT_EQ(result.Height(), result.track_adapter_settings().target_height());
- EXPECT_EQ(0.0, result.track_adapter_settings().max_frame_rate());
+ EXPECT_EQ(frame_rate, result.track_adapter_settings().max_frame_rate());
}
void CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(
- const VideoCaptureSettings& result) {
+ const VideoCaptureSettings& result,
+ double frame_rate = 0.0) {
EXPECT_EQ(
static_cast<double>(kMinScreenCastDimension) / kMaxScreenCastDimension,
result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(
static_cast<double>(kMaxScreenCastDimension) / kMinScreenCastDimension,
result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, frame_rate);
}
} // namespace
@@ -1296,7 +1298,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryExactFrameRate) {
EXPECT_EQ(kFrameRate, result.min_frame_rate());
EXPECT_EQ(kFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result, kFrameRate);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMinFrameRate) {
@@ -1375,7 +1377,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxFrameRate) {
EXPECT_EQ(base::Optional<double>(), result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
// kMaxFrameRate less than default
@@ -1389,7 +1392,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxFrameRate) {
EXPECT_EQ(base::Optional<double>(), result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
// kMaxFrameRate greater than the maximum allowed
@@ -1417,7 +1421,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxFrameRate) {
EXPECT_EQ(base::Optional<double>(), result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
}
@@ -1435,7 +1440,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryRangeFrameRate) {
EXPECT_EQ(kMinFrameRate, result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
{
@@ -1450,7 +1456,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryRangeFrameRate) {
EXPECT_EQ(kMinFrameRate, result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
{
@@ -1465,7 +1472,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryRangeFrameRate) {
EXPECT_EQ(kMinFrameRate, result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
}
@@ -1481,7 +1489,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealFrameRate) {
EXPECT_EQ(base::Optional<double>(), result.min_frame_rate());
EXPECT_EQ(base::Optional<double>(), result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kIdealFrameRate);
}
// Ideal greater than maximum.
@@ -1497,7 +1506,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealFrameRate) {
EXPECT_EQ(base::Optional<double>(), result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMaxFrameRate);
}
// Ideal less than minimum.
@@ -1512,7 +1522,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealFrameRate) {
EXPECT_EQ(kMinFrameRate, result.FrameRate());
EXPECT_EQ(base::Optional<double>(), result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kMinFrameRate);
}
// Ideal within range.
@@ -1530,7 +1541,8 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealFrameRate) {
EXPECT_EQ(kMinFrameRate, result.min_frame_rate());
EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result,
+ kIdealFrameRate);
}
}
@@ -1604,7 +1616,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_EQ(std::string(), result.device_id());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 10.0);
MediaTrackConstraintSetPlatform& advanced4 =
constraint_factory_.AddAdvanced();
@@ -1621,7 +1633,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_EQ(std::string(), result.device_id());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 10.0);
constraint_factory_.basic().width.SetIdeal(100);
constraint_factory_.basic().height.SetIdeal(100);
@@ -1638,7 +1650,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_EQ(std::string(), result.device_id());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 10.0);
constraint_factory_.basic().width.SetIdeal(2000);
constraint_factory_.basic().height.SetIdeal(1500);
@@ -1654,7 +1666,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_EQ(std::string(), result.device_id());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(5.0 / 4.0, result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 10.0);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedExactResolution) {
@@ -1744,7 +1756,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(1920.0 / 1080.0,
result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 60.0);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedNoiseReduction) {
@@ -1933,7 +1945,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_TRUE(result.HasValue());
EXPECT_EQ(40.0, result.FrameRate());
CheckNonFrameRateDefaults(result);
- CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result);
+ CheckTrackAdapterSettingsEqualsFormatDefaultAspectRatio(result, 40.0);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest,
@@ -1977,7 +1989,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
result.track_adapter_settings().min_aspect_ratio());
EXPECT_EQ(static_cast<double>(kMaxWidth) / kMinScreenCastDimension,
result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 90.0);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest,
@@ -2005,7 +2017,7 @@ TEST_F(MediaStreamConstraintsUtilVideoContentTest,
EXPECT_EQ(
static_cast<double>(kMaxScreenCastDimension) / kMinScreenCastDimension,
result.track_adapter_settings().max_aspect_ratio());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsFormat(result, 60.0);
}
TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedDeviceID) {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
index e327e976650..dcb574f36e0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
@@ -64,16 +64,25 @@ double NumericValueFitness(const NumericConstraint& constraint,
}
// Returns the fitness distance between the ideal value of |constraint| and the
-// closest value to it in the range [min, max].
-// If the ideal value is contained in the range, returns 1.
+// closest value to it in the range [min, max] if the constraint is supported.
+// If the constraint is present but not supported, returns 1 if there is no
+// ideal value (to account the failed boolean capability constraint) or 2
+// otherwise (to account the failed boolean capability constraint and failed
+// numeric ideal value constraint).
+// If the ideal value is contained in the range, returns 0.
// If there is no ideal value, returns 0;
// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance.
template <typename NumericConstraint>
-double NumericRangeFitness(
+double NumericRangeSupportFitness(
const NumericConstraint& constraint,
- const media_constraints::NumericRangeSet<decltype(constraint.Min())>&
- range) {
+ const media_constraints::NumericRangeSet<decltype(constraint.Min())>& range,
+ bool constraint_present,
+ bool constraint_supported) {
DCHECK(!range.IsEmpty());
+
+ if (constraint_present && !constraint_supported)
+ return 1.0 + (constraint.HasIdeal() ? 1.0 : 0.0);
+
if (!constraint.HasIdeal())
return 0.0;
@@ -83,7 +92,7 @@ double NumericRangeFitness(
else if (range.Min().has_value() && ideal < *range.Min())
return NumericConstraintFitnessDistance(ideal, *range.Min());
- return 1.0;
+ return 0.0; // |range| contains |ideal|
}
// Returns a custom distance between |native_value| and the ideal value and
@@ -290,9 +299,12 @@ class CandidateFormat {
static_cast<double>(track_settings_with_rescale.target_width()) /
track_settings_with_rescale.target_height();
DCHECK(!std::isnan(target_aspect_ratio));
- double target_frame_rate = track_settings_with_rescale.max_frame_rate();
- if (target_frame_rate == 0.0)
- target_frame_rate = NativeFrameRate();
+ double best_supported_frame_rate =
+ track_settings_with_rescale.max_frame_rate();
+ if (best_supported_frame_rate == 0.0 ||
+ best_supported_frame_rate > NativeFrameRate()) {
+ best_supported_frame_rate = NativeFrameRate();
+ }
track_fitness_with_rescale =
NumericValueFitness(basic_constraint_set.aspect_ratio,
@@ -302,7 +314,7 @@ class CandidateFormat {
NumericValueFitness(basic_constraint_set.width,
track_settings_with_rescale.target_width()) +
NumericValueFitness(basic_constraint_set.frame_rate,
- target_frame_rate);
+ best_supported_frame_rate);
}
double track_fitness_without_rescale = HUGE_VAL;
@@ -317,17 +329,19 @@ class CandidateFormat {
basic_constraint_set, resolution_set(), constrained_frame_rate(),
format(), false /* enable_rescale */);
DCHECK(!track_settings_without_rescale.target_size().has_value());
- double target_frame_rate =
+ double best_supported_frame_rate =
track_settings_without_rescale.max_frame_rate();
- if (target_frame_rate == 0.0)
- target_frame_rate = NativeFrameRate();
+ if (best_supported_frame_rate == 0.0 ||
+ best_supported_frame_rate > NativeFrameRate()) {
+ best_supported_frame_rate = NativeFrameRate();
+ }
track_fitness_without_rescale =
NumericValueFitness(basic_constraint_set.aspect_ratio,
NativeAspectRatio()) +
NumericValueFitness(basic_constraint_set.height, NativeHeight()) +
NumericValueFitness(basic_constraint_set.width, NativeWidth()) +
NumericValueFitness(basic_constraint_set.frame_rate,
- target_frame_rate);
+ best_supported_frame_rate);
}
}
@@ -457,19 +471,27 @@ class PTZDeviceState {
return pan_set_.IsEmpty() || tilt_set_.IsEmpty() || zoom_set_.IsEmpty();
}
- double Fitness(const MediaTrackConstraintSetPlatform& basic_set) const {
- return NumericRangeFitness(basic_set.pan, pan_set_) +
- NumericRangeFitness(basic_set.tilt, tilt_set_) +
- NumericRangeFitness(basic_set.zoom, zoom_set_);
+ double Fitness(
+ const MediaTrackConstraintSetPlatform& basic_set,
+ const media::VideoCaptureControlSupport& control_support) const {
+ return NumericRangeSupportFitness(basic_set.pan, pan_set_,
+ basic_set.pan.IsPresent(),
+ control_support.pan) +
+ NumericRangeSupportFitness(basic_set.tilt, tilt_set_,
+ basic_set.tilt.IsPresent(),
+ control_support.tilt) +
+ NumericRangeSupportFitness(basic_set.zoom, zoom_set_,
+ basic_set.zoom.IsPresent(),
+ control_support.zoom);
}
const char* FailedConstraintName() const {
MediaTrackConstraintSetPlatform dummy;
- if (!pan_set_.IsEmpty())
+ if (pan_set_.IsEmpty())
return dummy.pan.GetName();
- if (!tilt_set_.IsEmpty())
+ if (tilt_set_.IsEmpty())
return dummy.tilt.GetName();
- if (!zoom_set_.IsEmpty())
+ if (zoom_set_.IsEmpty())
return dummy.zoom.GetName();
// No failed constraint.
@@ -557,17 +579,17 @@ bool DeviceSatisfiesConstraintSet(
return false;
}
- if (constraint_set.pan.IsPresent() && !device.pan_tilt_zoom_supported) {
+ if (constraint_set.pan.HasMandatory() && !device.control_support.pan) {
UpdateFailedConstraintName(constraint_set.pan, failed_constraint_name);
return false;
}
- if (constraint_set.tilt.IsPresent() && !device.pan_tilt_zoom_supported) {
+ if (constraint_set.tilt.HasMandatory() && !device.control_support.tilt) {
UpdateFailedConstraintName(constraint_set.tilt, failed_constraint_name);
return false;
}
- if (constraint_set.zoom.IsPresent() && !device.pan_tilt_zoom_supported) {
+ if (constraint_set.zoom.HasMandatory() && !device.control_support.zoom) {
UpdateFailedConstraintName(constraint_set.zoom, failed_constraint_name);
return false;
}
@@ -614,7 +636,7 @@ double CandidateFitness(const DeviceInfo& device,
const MediaTrackConstraintSetPlatform& constraint_set,
VideoTrackAdapterSettings* track_settings) {
return DeviceFitness(device, constraint_set) +
- ptz_state.Fitness(constraint_set) +
+ ptz_state.Fitness(constraint_set, device.control_support) +
candidate_format.Fitness(constraint_set, track_settings) +
OptionalBoolFitness(noise_reduction,
constraint_set.goog_noise_reduction);
@@ -669,14 +691,14 @@ VideoInputDeviceCapabilities::VideoInputDeviceCapabilities() = default;
VideoInputDeviceCapabilities::VideoInputDeviceCapabilities(
String device_id,
String group_id,
+ const media::VideoCaptureControlSupport& control_support,
Vector<media::VideoCaptureFormat> formats,
- media::VideoFacingMode facing_mode,
- bool pan_tilt_zoom_supported)
+ media::VideoFacingMode facing_mode)
: device_id(std::move(device_id)),
group_id(std::move(group_id)),
+ control_support(control_support),
formats(std::move(formats)),
- facing_mode(facing_mode),
- pan_tilt_zoom_supported(pan_tilt_zoom_supported) {}
+ facing_mode(facing_mode) {}
VideoInputDeviceCapabilities::VideoInputDeviceCapabilities(
VideoInputDeviceCapabilities&& other) = default;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
index ecb2aa191cc..ac8ffa0c4be 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
@@ -29,11 +29,12 @@ MODULES_EXPORT MediaStreamTrackPlatform::FacingMode ToPlatformFacingMode(
// This is a temporary struct to bridge blink and content mojo types.
struct MODULES_EXPORT VideoInputDeviceCapabilities {
- VideoInputDeviceCapabilities(String device_id,
- String group_id,
- Vector<media::VideoCaptureFormat> formats,
- media::VideoFacingMode facing_mode,
- bool pan_tilt_zoom_supported);
+ VideoInputDeviceCapabilities(
+ String device_id,
+ String group_id,
+ const media::VideoCaptureControlSupport& control_support,
+ Vector<media::VideoCaptureFormat> formats,
+ media::VideoFacingMode facing_mode);
VideoInputDeviceCapabilities();
VideoInputDeviceCapabilities(VideoInputDeviceCapabilities&& other);
VideoInputDeviceCapabilities& operator=(VideoInputDeviceCapabilities&& other);
@@ -41,9 +42,9 @@ struct MODULES_EXPORT VideoInputDeviceCapabilities {
String device_id;
String group_id;
+ media::VideoCaptureControlSupport control_support;
Vector<media::VideoCaptureFormat> formats;
media::VideoFacingMode facing_mode;
- bool pan_tilt_zoom_supported;
};
struct MODULES_EXPORT VideoDeviceCaptureCapabilities {
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
index 1acb3c4b4b4..3eabce2fd82 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
@@ -24,14 +24,12 @@ const char kDeviceID2[] = "fake_device_2";
const char kDeviceID3[] = "fake_device_3";
const char kDeviceID4[] = "fake_device_4";
const char kDeviceID5[] = "fake_device_5";
-const char kDeviceID6[] = "fake_device_6";
const char kGroupID1[] = "fake_group_1";
const char kGroupID2[] = "fake_group_2";
const char kGroupID3[] = "fake_group_3";
const char kGroupID4[] = "fake_group_4";
const char kGroupID5[] = "fake_group_5";
-const char kGroupID6[] = "fake_group_6";
const std::vector<DoubleConstraint MediaTrackConstraintSetPlatform::*>
kPanTiltZoomConstraints = {
@@ -52,8 +50,6 @@ void CheckTrackAdapterSettingsEqualsResolution(
void CheckTrackAdapterSettingsEqualsFrameRate(
const VideoCaptureSettings& settings,
double value = 0.0) {
- if (value >= settings.FrameRate())
- value = 0.0;
EXPECT_EQ(value, settings.track_adapter_settings().max_frame_rate());
}
@@ -96,7 +92,9 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
media::VideoCaptureFormat(gfx::Size(1000, 1000), 20.0f,
media::PIXEL_FORMAT_I420),
};
- device.pan_tilt_zoom_supported = true;
+ device.control_support.pan = false;
+ device.control_support.tilt = false;
+ device.control_support.zoom = false;
capabilities_.device_capabilities.push_back(std::move(device));
// A low-resolution device.
@@ -117,7 +115,9 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
media::VideoCaptureFormat(gfx::Size(800, 600), 20.0f,
media::PIXEL_FORMAT_I420),
};
- device.pan_tilt_zoom_supported = true;
+ device.control_support.pan = true;
+ device.control_support.tilt = true;
+ device.control_support.zoom = true;
capabilities_.device_capabilities.push_back(std::move(device));
// A high-resolution device.
@@ -149,7 +149,9 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
media::VideoCaptureFormat(gfx::Size(2304, 1536), 10.0f,
media::PIXEL_FORMAT_I420),
};
- device.pan_tilt_zoom_supported = true;
+ device.control_support.pan = true;
+ device.control_support.tilt = true;
+ device.control_support.zoom = true;
capabilities_.device_capabilities.push_back(std::move(device));
// A depth capture device.
@@ -158,6 +160,9 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
device.facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT;
device.formats = {media::VideoCaptureFormat(gfx::Size(640, 480), 30.0f,
media::PIXEL_FORMAT_Y16)};
+ device.control_support.pan = true;
+ device.control_support.tilt = true;
+ device.control_support.zoom = true;
capabilities_.device_capabilities.push_back(std::move(device));
// A device that reports invalid frame rates. These devices exist and should
@@ -173,16 +178,9 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
media::VideoCaptureFormat(gfx::Size(500, 500), 0.1f,
media::PIXEL_FORMAT_I420),
};
- device.pan_tilt_zoom_supported = true;
- capabilities_.device_capabilities.push_back(std::move(device));
-
- // A camera device without PTZ.
- device.device_id = kDeviceID6;
- device.group_id = kGroupID6;
- device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
- device.formats = {media::VideoCaptureFormat(gfx::Size(640, 480), 30.0f,
- media::PIXEL_FORMAT_I420)};
- device.pan_tilt_zoom_supported = false;
+ device.control_support.pan = true;
+ device.control_support.tilt = true;
+ device.control_support.zoom = true;
capabilities_.device_capabilities.push_back(std::move(device));
capabilities_.noise_reduction_capabilities = {
@@ -195,7 +193,6 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
low_res_device_ = &capabilities_.device_capabilities[1];
high_res_device_ = &capabilities_.device_capabilities[2];
invalid_frame_rate_device_ = &capabilities_.device_capabilities[4];
- no_ptz_device_ = &capabilities_.device_capabilities[5];
default_closest_format_ = &default_device_->formats[1];
low_res_closest_format_ = &low_res_device_->formats[2];
high_res_closest_format_ = &high_res_device_->formats[3];
@@ -213,7 +210,6 @@ class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
const VideoInputDeviceCapabilities* low_res_device_;
const VideoInputDeviceCapabilities* high_res_device_;
const VideoInputDeviceCapabilities* invalid_frame_rate_device_;
- const VideoInputDeviceCapabilities* no_ptz_device_;
// Closest formats to the default settings.
const media::VideoCaptureFormat* default_closest_format_;
const media::VideoCaptureFormat* low_res_closest_format_;
@@ -427,38 +423,30 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
- OverconstrainedOnPanTiltZoom) {
+ OverconstrainedOnMandatoryPanTiltZoom) {
for (auto& constraint : kPanTiltZoomConstraints) {
constraint_factory_.Reset();
- constraint_factory_.basic().device_id.SetExact(no_ptz_device_->device_id);
- (constraint_factory_.basic().*constraint).SetIdeal(1);
- auto result = SelectSettings();
- EXPECT_FALSE(result.HasValue());
- EXPECT_EQ((constraint_factory_.basic().*constraint).GetName(),
- result.failed_constraint_name());
-
- constraint_factory_.Reset();
- constraint_factory_.basic().device_id.SetExact(no_ptz_device_->device_id);
+ constraint_factory_.basic().device_id.SetExact(default_device_->device_id);
(constraint_factory_.basic().*constraint).SetMin(1);
- result = SelectSettings();
+ auto result = SelectSettings();
EXPECT_FALSE(result.HasValue());
- EXPECT_EQ((constraint_factory_.basic().*constraint).GetName(),
+ EXPECT_EQ(constraint_factory_.basic().device_id.GetName(),
result.failed_constraint_name());
constraint_factory_.Reset();
- constraint_factory_.basic().device_id.SetExact(no_ptz_device_->device_id);
+ constraint_factory_.basic().device_id.SetExact(default_device_->device_id);
(constraint_factory_.basic().*constraint).SetMax(1);
result = SelectSettings();
EXPECT_FALSE(result.HasValue());
- EXPECT_EQ((constraint_factory_.basic().*constraint).GetName(),
+ EXPECT_EQ(constraint_factory_.basic().device_id.GetName(),
result.failed_constraint_name());
constraint_factory_.Reset();
- constraint_factory_.basic().device_id.SetExact(no_ptz_device_->device_id);
+ constraint_factory_.basic().device_id.SetExact(default_device_->device_id);
(constraint_factory_.basic().*constraint).SetExact(1);
result = SelectSettings();
EXPECT_FALSE(result.HasValue());
- EXPECT_EQ((constraint_factory_.basic().*constraint).GetName(),
+ EXPECT_EQ(constraint_factory_.basic().device_id.GetName(),
result.failed_constraint_name());
}
}
@@ -1194,7 +1182,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFrameRateRange) {
// format has a frame rate included in the requested range.
EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
EXPECT_EQ(*default_closest_format_, result.Format());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, kMaxFrameRate);
}
{
@@ -1211,7 +1200,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFrameRateRange) {
// range. The default resolution should be preferred as secondary criterion.
EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
EXPECT_EQ(*low_res_closest_format_, result.Format());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, kMaxFrameRate);
}
{
@@ -1230,7 +1220,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFrameRateRange) {
EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
EXPECT_EQ(1280, result.Width());
EXPECT_EQ(720, result.Height());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, kMaxFrameRate);
}
}
@@ -1294,7 +1285,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealFrameRate) {
EXPECT_EQ(1280, result.Width());
EXPECT_EQ(720, result.Height());
EXPECT_EQ(60, result.FrameRate());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate);
}
}
@@ -1896,8 +1888,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactPanTiltZoom) {
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The algorithm should prefer the first device that supports PTZ natively,
- // which is the default device.
- EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
+ // which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_EQ(3, result.pan().value());
else if (constraint == &MediaTrackConstraintSetPlatform::tilt)
@@ -1914,8 +1906,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinPanTiltZoom) {
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The algorithm should prefer the first device that supports PTZ
- // natively, which is the default device.
- EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
+ // natively, which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_EQ(2, result.pan().value());
else if (constraint == &MediaTrackConstraintSetPlatform::tilt)
@@ -1932,8 +1924,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxPanTiltZoom) {
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The algorithm should prefer the first device that supports PTZ
- // natively, which is the default device.
- EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
+ // natively, which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_EQ(4, result.pan().value());
else if (constraint == &MediaTrackConstraintSetPlatform::tilt)
@@ -1951,8 +1943,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryPanTiltZoomRange) {
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The algorithm should prefer the first device that supports PTZ
- // natively, which is the default device.
- EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
+ // natively, which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_EQ(2, result.pan().value());
else if (constraint == &MediaTrackConstraintSetPlatform::tilt)
@@ -1969,8 +1961,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealPanTiltZoom) {
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The algorithm should select the first device that supports the ideal PTZ
- // constraint natively, which is the default device.
- EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
+ // constraint natively, which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_EQ(3, result.pan().value());
else if (constraint == &MediaTrackConstraintSetPlatform::tilt)
@@ -1980,6 +1972,52 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealPanTiltZoom) {
}
}
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, PresentPanTiltZoom) {
+ for (auto& constraint : kPanTiltZoomConstraints) {
+ constraint_factory_.Reset();
+ (constraint_factory_.basic().*constraint).SetIsPresent(true);
+ auto result = SelectSettings();
+ EXPECT_TRUE(result.HasValue());
+ // The algorithm should select the first device that supports the boolean
+ // PTZ constraint natively, which is the low-res device.
+ EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
+ }
+}
+
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
+ PresentPanTiltZoomOnSystemWithoutPanTiltZoomCamera) {
+ // Simulate a system with camera that does not support PTZ.
+ // Manually adding device capabilities because VideoDeviceCaptureCapabilities
+ // is move only.
+ VideoDeviceCaptureCapabilities capabilities;
+ VideoInputDeviceCapabilities device;
+ device.device_id = kDeviceID1;
+ device.facing_mode = media::MEDIA_VIDEO_FACING_NONE;
+ device.formats = {
+ media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f,
+ media::PIXEL_FORMAT_I420),
+ };
+ device.control_support.pan = false;
+ device.control_support.tilt = false;
+ device.control_support.zoom = false;
+ capabilities.device_capabilities.push_back(std::move(device));
+ capabilities.noise_reduction_capabilities = {
+ base::Optional<bool>(),
+ base::Optional<bool>(true),
+ base::Optional<bool>(false),
+ };
+
+ for (auto& constraint : kPanTiltZoomConstraints) {
+ constraint_factory_.Reset();
+ (constraint_factory_.basic().*constraint).SetIsPresent(true);
+ auto constraints = constraint_factory_.CreateMediaConstraints();
+ auto result = SelectSettingsVideoDeviceCapture(capabilities, constraints);
+ EXPECT_TRUE(result.HasValue());
+ // The algorithm should select one device, even if it doesn't support PTZ.
+ EXPECT_EQ(std::string(kDeviceID1), result.device_id());
+ }
+}
+
// The "Advanced" tests check selection criteria involving advanced constraint
// sets.
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
@@ -2347,7 +2385,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
// set.
EXPECT_EQ(40.0, result.FrameRate());
CheckTrackAdapterSettingsEqualsResolution(result);
- CheckTrackAdapterSettingsEqualsFrameRate(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, 40.0);
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
@@ -2389,7 +2427,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
EXPECT_EQ(30.0, result.FrameRate());
EXPECT_GE(1920, result.Width());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, 30.0);
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
@@ -2414,7 +2453,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
EXPECT_EQ(60.0, result.FrameRate());
EXPECT_GE(1080, result.Height());
- CheckTrackAdapterSettingsEqualsFormat(result);
+ CheckTrackAdapterSettingsEqualsResolution(result);
+ CheckTrackAdapterSettingsEqualsFrameRate(result, 60.0);
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedDeviceID) {
@@ -2557,7 +2597,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
MediaTrackConstraintSetPlatform& advanced2 =
constraint_factory_.AddAdvanced();
- advanced2.device_id.SetExact({no_ptz_device_->device_id});
+ advanced2.device_id.SetExact({default_device_->device_id});
(advanced2.*constraint).SetExact(4);
MediaTrackConstraintSetPlatform& advanced3 =
@@ -2633,13 +2673,13 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedPanTiltZoom) {
for (auto& constraint : kPanTiltZoomConstraints) {
constraint_factory_.Reset();
- constraint_factory_.basic().device_id.SetExact(no_ptz_device_->device_id);
+ constraint_factory_.basic().device_id.SetExact(default_device_->device_id);
MediaTrackConstraintSetPlatform& advanced =
constraint_factory_.AddAdvanced();
(advanced.*constraint).SetExact(3);
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
- EXPECT_EQ(no_ptz_device_->device_id.Utf8(), result.device_id());
+ EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
// The advanced set must be ignored because the device does not support PTZ.
if (constraint == &MediaTrackConstraintSetPlatform::pan)
EXPECT_FALSE(result.pan().has_value());
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 6604b5e09db..e51c6fa9923 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
@@ -27,7 +27,9 @@
#include <memory>
+#include "base/feature_list.h"
#include "base/strings/stringprintf.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
@@ -40,6 +42,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/deprecation.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/modules/imagecapture/image_capture.h"
#include "third_party/blink/renderer/modules/mediastream/apply_constraints_request.h"
#include "third_party/blink/renderer/modules/mediastream/media_constraints_impl.h"
@@ -256,9 +259,18 @@ MediaStreamTrack::MediaStreamTrack(ExecutionContext* context,
image_capture_ = MakeGarbageCollected<ImageCapture>(
context, this, pan_tilt_zoom_allowed, std::move(callback));
} else {
- execution_context_->GetTaskRunner(TaskType::kInternalMedia)
- ->PostTask(FROM_HERE, std::move(callback));
+ if (execution_context_) {
+ execution_context_->GetTaskRunner(TaskType::kInternalMedia)
+ ->PostTask(FROM_HERE, std::move(callback));
+ } else {
+ std::move(callback).Run();
+ }
}
+
+ // Note that both 'live' and 'muted' correspond to a 'live' ready state in the
+ // web API.
+ if (ready_state_ != MediaStreamSource::kReadyStateEnded)
+ EnsureFeatureHandleForScheduler();
}
MediaStreamTrack::~MediaStreamTrack() = default;
@@ -402,6 +414,7 @@ void MediaStreamTrack::stopTrack(ExecutionContext* execution_context) {
return;
ready_state_ = MediaStreamSource::kReadyStateEnded;
+ feature_handle_for_scheduler_.reset();
UserMediaController* user_media =
UserMediaController::From(To<LocalDOMWindow>(execution_context));
if (user_media)
@@ -730,19 +743,25 @@ void MediaStreamTrack::SourceChangedState() {
if (Ended())
return;
+ // Note that both 'live' and 'muted' correspond to a 'live' ready state in the
+ // web API, hence the following logic around |feature_handle_for_scheduler_|.
+
ready_state_ = component_->Source()->GetReadyState();
switch (ready_state_) {
case MediaStreamSource::kReadyStateLive:
component_->SetMuted(false);
DispatchEvent(*Event::Create(event_type_names::kUnmute));
+ EnsureFeatureHandleForScheduler();
break;
case MediaStreamSource::kReadyStateMuted:
component_->SetMuted(true);
DispatchEvent(*Event::Create(event_type_names::kMute));
+ EnsureFeatureHandleForScheduler();
break;
case MediaStreamSource::kReadyStateEnded:
DispatchEvent(*Event::Create(event_type_names::kEnded));
PropagateTrackEnded();
+ feature_handle_for_scheduler_.reset();
break;
}
SendLogMessage(
@@ -813,4 +832,24 @@ void MediaStreamTrack::Trace(Visitor* visitor) const {
EventTargetWithInlineData::Trace(visitor);
}
+void MediaStreamTrack::EnsureFeatureHandleForScheduler() {
+ if (feature_handle_for_scheduler_)
+ return;
+ LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(GetExecutionContext());
+ // Ideally we'd use To<LocalDOMWindow>, but in unittests the ExecutionContext
+ // may not be a LocalDOMWindow.
+ if (!window)
+ return;
+ // This can happen for detached frames.
+ if (!window->GetFrame())
+ return;
+ feature_handle_for_scheduler_ =
+ window->GetFrame()->GetFrameScheduler()->RegisterFeature(
+ SchedulingPolicy::Feature::kWebRTC,
+ base::FeatureList::IsEnabled(features::kOptOutWebRTCFromAllThrottling)
+ ? SchedulingPolicy{SchedulingPolicy::DisableAllThrottling()}
+ : SchedulingPolicy{
+ SchedulingPolicy::DisableAggressiveThrottling()});
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h
index f7172eabb90..4c46daff82d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.h
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
@@ -125,6 +126,15 @@ class MODULES_EXPORT MediaStreamTrack
std::string GetTrackLogString() const;
+ // Ensures that |feature_handle_for_scheduler_| is initialized.
+ void EnsureFeatureHandleForScheduler();
+
+ // This handle notifies the scheduler about a live media stream track
+ // associated with a frame. The handle should be destroyed when the track
+ // is stopped.
+ FrameScheduler::SchedulingAffectingFeatureHandle
+ feature_handle_for_scheduler_;
+
MediaStreamSource::ReadyState ready_state_;
HeapHashSet<Member<MediaStream>> registered_media_streams_;
bool is_iterating_registered_media_streams_ = false;
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index 61b262a226d..9849e59fee7 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -614,9 +614,16 @@ void MediaStreamVideoTrack::GetSettings(
void MediaStreamVideoTrack::OnReadyStateChanged(
WebMediaStreamSource::ReadyState state) {
DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
- for (auto* sink : sinks_)
+
+ // Copy the vectors first, since sinks might DisconnectFromTrack() and
+ // invalidate iterators.
+
+ Vector<WebMediaStreamSink*> sinks_copy(sinks_);
+ for (auto* sink : sinks_copy)
sink->OnReadyStateChanged(state);
- for (auto* encoded_sink : encoded_sinks_)
+
+ Vector<WebMediaStreamSink*> encoded_sinks_copy(encoded_sinks_);
+ for (auto* encoded_sink : encoded_sinks_copy)
encoded_sink->OnReadyStateChanged(state);
}
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index b4361a66e84..3d7655368e0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -292,8 +292,8 @@ Vector<blink::VideoInputDeviceCapabilities> ToVideoInputDeviceCapabilities(
Vector<blink::VideoInputDeviceCapabilities> capabilities;
for (const auto& capability : input_capabilities) {
capabilities.emplace_back(capability->device_id, capability->group_id,
- capability->formats, capability->facing_mode,
- capability->pan_tilt_zoom_supported);
+ capability->control_support, capability->formats,
+ capability->facing_mode);
}
return capabilities;
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 877e0eb541e..b32d6a7b165 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
@@ -339,7 +339,21 @@ UserMediaRequest* UserMediaRequest::Create(
if (error_state.HadException())
return nullptr;
- if (media_type == UserMediaRequest::MediaType::kDisplayMedia) {
+ if (media_type == UserMediaRequest::MediaType::kUserMedia &&
+ !video.IsNull()) {
+ if (video.Basic().pan.HasMandatory()) {
+ error_state.ThrowTypeError("Mandatory pan constraint is not supported");
+ return nullptr;
+ }
+ if (video.Basic().tilt.HasMandatory()) {
+ error_state.ThrowTypeError("Mandatory tilt constraint is not supported");
+ return nullptr;
+ }
+ if (video.Basic().zoom.HasMandatory()) {
+ error_state.ThrowTypeError("Mandatory zoom constraint is not supported");
+ return nullptr;
+ }
+ } else if (media_type == UserMediaRequest::MediaType::kDisplayMedia) {
// https://w3c.github.io/mediacapture-screen-share/#mediadevices-additions
// MediaDevices Additions
// The user agent MUST reject audio-only requests.
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
index 459b9d31c8e..48206460a62 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
@@ -1221,7 +1221,6 @@ void WebMediaPlayerMS::ActivateSurfaceLayerForVideo() {
*compositor_task_runner_, FROM_HERE,
CrossThreadBindOnce(&WebMediaPlayerMSCompositor::EnableSubmission,
compositor_, bridge_->GetSurfaceId(),
- bridge_->GetLocalSurfaceIdAllocationTime(),
video_transformation_, IsInPictureInPicture()));
// If the element is already in Picture-in-Picture mode, it means that it
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc
index 02fa58e2300..a296140c1d0 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.cc
@@ -244,7 +244,6 @@ void WebMediaPlayerMSCompositor::SetIsSurfaceVisible(bool state) {
// submission. Do this along with the VideoFrameSubmitter refactor.
void WebMediaPlayerMSCompositor::EnableSubmission(
const viz::SurfaceId& id,
- base::TimeTicks local_surface_id_allocation_time,
media::VideoTransformation transformation,
bool force_submit) {
DCHECK(video_frame_compositor_task_runner_->BelongsToCurrentThread());
@@ -257,7 +256,7 @@ void WebMediaPlayerMSCompositor::EnableSubmission(
submitter_->SetRotation(transformation.rotation);
submitter_->SetForceSubmit(force_submit);
- submitter_->EnableSubmission(id, local_surface_id_allocation_time);
+ submitter_->EnableSubmission(id);
video_frame_provider_client_ = submitter_.get();
if (!stopped_)
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h
index 33b0c579ec4..10d01b8528e 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_compositor.h
@@ -86,7 +86,6 @@ class MODULES_EXPORT WebMediaPlayerMSCompositor
// submit video frames given by WebMediaPlayerMSCompositor.
virtual void EnableSubmission(
const viz::SurfaceId& id,
- base::TimeTicks local_surface_id_allocation_time,
media::VideoTransformation transformation,
bool force_submit);
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc
index c7dcd28718e..3dedcae704c 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms_test.cc
@@ -62,7 +62,6 @@ class MockSurfaceLayerBridge : public WebSurfaceLayerBridge {
MOCK_CONST_METHOD0(GetCcLayer, cc::Layer*());
MOCK_CONST_METHOD0(GetFrameSinkId, const viz::FrameSinkId&());
MOCK_CONST_METHOD0(GetSurfaceId, const viz::SurfaceId&());
- MOCK_CONST_METHOD0(GetLocalSurfaceIdAllocationTime, base::TimeTicks());
MOCK_METHOD1(SetContentsOpaque, void(bool));
MOCK_METHOD0(CreateSurfaceLayer, void());
MOCK_METHOD0(ClearSurfaceId, void());
@@ -188,6 +187,10 @@ class FakeWebMediaPlayerDelegate
EXPECT_EQ(delegate_id_, delegate_id);
}
+ void DidDisableAudioOutputSinkChanges(int delegate_id) override {
+ EXPECT_EQ(delegate_id_, delegate_id);
+ }
+
private:
int delegate_id_ = 1234;
Observer* observer_ = nullptr;
@@ -429,7 +432,7 @@ class MockWebVideoFrameSubmitter : public WebVideoFrameSubmitter {
// WebVideoFrameSubmitter implementation.
MOCK_METHOD0(StopUsingProvider, void());
MOCK_METHOD0(DidReceiveFrame, void());
- MOCK_METHOD2(EnableSubmission, void(viz::SurfaceId, base::TimeTicks));
+ MOCK_METHOD1(EnableSubmission, void(viz::SurfaceId));
MOCK_METHOD0(StartRendering, void());
MOCK_METHOD0(StopRendering, void());
MOCK_METHOD1(MockInitialize, void(cc::VideoFrameProvider*));
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 c0aeb9ea0d6..2872dcb23d4 100644
--- a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -75,6 +75,7 @@ _idl_imports = [
"//third_party/blink/renderer/modules/encryptedmedia/idls.gni",
"//third_party/blink/renderer/modules/eventsource/idls.gni",
"//third_party/blink/renderer/modules/filesystem/idls.gni",
+ "//third_party/blink/renderer/modules/file_system_access/idls.gni",
"//third_party/blink/renderer/modules/font_access/idls.gni",
"//third_party/blink/renderer/modules/gamepad/idls.gni",
"//third_party/blink/renderer/modules/geolocation/idls.gni",
@@ -93,7 +94,6 @@ _idl_imports = [
"//third_party/blink/renderer/modules/mediasession/idls.gni",
"//third_party/blink/renderer/modules/mediasource/idls.gni",
"//third_party/blink/renderer/modules/mediastream/idls.gni",
- "//third_party/blink/renderer/modules/native_file_system/idls.gni",
"//third_party/blink/renderer/modules/native_io/idls.gni",
"//third_party/blink/renderer/modules/navigatorcontentutils/idls.gni",
"//third_party/blink/renderer/modules/netinfo/idls.gni",
@@ -108,6 +108,7 @@ _idl_imports = [
"//third_party/blink/renderer/modules/presentation/idls.gni",
"//third_party/blink/renderer/modules/push_messaging/idls.gni",
"//third_party/blink/renderer/modules/quota/idls.gni",
+ "//third_party/blink/renderer/modules/direct_sockets/idls.gni",
"//third_party/blink/renderer/modules/remoteplayback/idls.gni",
"//third_party/blink/renderer/modules/sanitizer_api/idls.gni",
"//third_party/blink/renderer/modules/scheduler/idls.gni",
diff --git a/chromium/third_party/blink/renderer/modules/modules_initializer.cc b/chromium/third_party/blink/renderer/modules/modules_initializer.cc
index 505f7bd71e0..e1cfdcbddb1 100644
--- a/chromium/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/chromium/third_party/blink/renderer/modules/modules_initializer.cc
@@ -62,6 +62,7 @@
#include "third_party/blink/renderer/modules/launch/file_handling_expiry_impl.h"
#include "third_party/blink/renderer/modules/launch/web_launch_service_impl.h"
#include "third_party/blink/renderer/modules/manifest/manifest_manager.h"
+#include "third_party/blink/renderer/modules/media/audio/audio_renderer_sink_cache.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/mediasource/media_source_registry_impl.h"
#include "third_party/blink/renderer/modules/mediastream/user_media_client.h"
@@ -187,6 +188,7 @@ void ModulesInitializer::InstallSupplements(LocalFrame& frame) const {
DCHECK(WebLocalFrameImpl::FromFrame(&frame)->Client());
InspectorAccessibilityAgent::ProvideTo(&frame);
ImageDownloaderImpl::ProvideTo(frame);
+ AudioRendererSinkCache::InstallFrameObserver(frame);
}
MediaControls* ModulesInitializer::CreateMediaControls(
@@ -233,8 +235,7 @@ void ModulesInitializer::OnClearWindowObjectInMainWorld(
// TODO(nhiroki): Figure out why ServiceWorkerContainer needs to be eagerly
// initialized.
- auto& frame_loader = document.GetFrame()->Loader();
- if (!frame_loader.StateMachine()->IsDisplayingInitialEmptyDocument())
+ if (!document.IsInitialEmptyDocument())
NavigatorServiceWorker::From(window);
DOMWindowStorageController::From(document);
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options.idl b/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options.idl
deleted file mode 100644
index 8e907eb2629..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options.idl
+++ /dev/null
@@ -1,18 +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.
-
-// https://wicg.github.io/native-file-system/#enumdef-choosefilesystementriestype
-enum ChooseFileSystemEntriesType {
- "open-file",
- "save-file",
- "open-directory",
-};
-
-// https://wicg.github.io/native-file-system/#dictdef-choosefilesystementriesoptions
-dictionary ChooseFileSystemEntriesOptions {
- ChooseFileSystemEntriesType type = "open-file";
- boolean multiple = false;
- sequence<ChooseFileSystemEntriesOptionsAccepts> accepts;
- boolean excludeAcceptAllOption = false;
-};
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options_accepts.idl b/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options_accepts.idl
deleted file mode 100644
index 6b95a2b240d..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_file_system/choose_file_system_entries_options_accepts.idl
+++ /dev/null
@@ -1,10 +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.
-
-// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
-dictionary ChooseFileSystemEntriesOptionsAccepts {
- DOMString description;
- sequence<DOMString> mimeTypes;
- sequence<DOMString> extensions;
-};
diff --git a/chromium/third_party/blink/renderer/modules/native_file_system/get_system_directory_options.idl b/chromium/third_party/blink/renderer/modules/native_file_system/get_system_directory_options.idl
deleted file mode 100644
index 0d51d293fd5..00000000000
--- a/chromium/third_party/blink/renderer/modules/native_file_system/get_system_directory_options.idl
+++ /dev/null
@@ -1,13 +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.
-
-// https://wicg.github.io/native-file-system/#enumdef-systemdirectorytype
-enum SystemDirectoryType {
- "sandbox"
-};
-
-// https://wicg.github.io/native-file-system/#dictdef-getsystemdirectoryoptions
-dictionary GetSystemDirectoryOptions {
- required SystemDirectoryType type;
-};
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 f168e6b7bf7..832d56c7418 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
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h"
#include "base/stl_util.h"
+#include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.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/web_local_frame_impl.h"
@@ -36,6 +37,7 @@
#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/text/string_builder.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
@@ -45,21 +47,6 @@ namespace {
const char kToken[] = "%s";
-// Changes to this list must be kept in sync with the browser-side checks in
-// /chrome/common/custom_handlers/protocol_handler.cc.
-static const HashSet<String>& SupportedSchemes() {
- DEFINE_STATIC_LOCAL(
- HashSet<String>, supported_schemes,
- ({
- "bitcoin", "cabal", "dat", "did", "dweb", "ethereum",
- "geo", "hyper", "im", "ipfs", "ipns", "irc",
- "ircs", "magnet", "mailto", "mms", "news", "nntp",
- "openpgp4fpr", "sip", "sms", "smsto", "ssb", "ssh",
- "tel", "urn", "webcal", "wtai", "xmpp",
- }));
- return supported_schemes;
-}
-
static bool VerifyCustomHandlerURLSecurity(const LocalDOMWindow& window,
const KURL& full_url,
String& error_message) {
@@ -108,22 +95,6 @@ static bool VerifyCustomHandlerURL(const LocalDOMWindow& window,
return true;
}
-// HTML5 requires that schemes with the |web+| prefix contain one or more
-// ASCII alphas after that prefix.
-static bool IsValidWebSchemeName(const String& protocol) {
- if (protocol.length() < 5)
- return false;
-
- unsigned protocol_length = protocol.length();
- for (unsigned i = 4; i < protocol_length; i++) {
- char c = protocol[i];
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
- return false;
- }
- }
- return true;
-}
-
} // namespace
bool VerifyCustomHandlerScheme(const String& scheme, String& error_string) {
@@ -133,24 +104,25 @@ bool VerifyCustomHandlerScheme(const String& scheme, String& error_string) {
return false;
}
- if (scheme.StartsWithIgnoringASCIICase("web+")) {
- if (IsValidWebSchemeName(scheme))
- return true;
- error_string =
- "The scheme name '" + scheme +
- "' is not allowed. Schemes starting with 'web+' must be followed by "
- "one or more ASCII letters.";
+ bool has_custom_scheme_prefix;
+ StringUTF8Adaptor scheme_adaptor(scheme);
+ if (!IsValidCustomHandlerScheme(scheme_adaptor.AsStringPiece(),
+ has_custom_scheme_prefix)) {
+ if (has_custom_scheme_prefix) {
+ error_string =
+ "The scheme name '" + scheme +
+ "' is not allowed. Schemes starting with 'web+' must be followed by "
+ "one or more ASCII letters.";
+ } else {
+ error_string = "The scheme '" + scheme +
+ "' doesn't belong to the scheme allowlist. "
+ "Please prefix non-allowlisted schemes "
+ "with the string 'web+'.";
+ }
return false;
}
- if (SupportedSchemes().Contains(scheme.LowerASCII()))
- return true;
-
- error_string = "The scheme '" + scheme +
- "' doesn't belong to the scheme allowlist. "
- "Please prefix non-allowlisted schemes "
- "with the string 'web+'.";
- return false;
+ return true;
}
bool VerifyCustomHandlerURLSyntax(const KURL& full_url,
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc
index df9dfaae935..82d73c04232 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_reader.cc
@@ -162,7 +162,7 @@ void NDEFReader::OnRequestPermission(const NDEFScanOptions* options,
UseCounter::Count(GetExecutionContext(), WebFeature::kWebNfcAPI);
GetNfcProxy()->StartReading(
- this, options,
+ this,
WTF::Bind(&NDEFReader::OnScanRequestCompleted, WrapPersistent(this)));
}
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_scan_options.idl b/chromium/third_party/blink/renderer/modules/nfc/ndef_scan_options.idl
index cf20cf59f6d..767635aa507 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_scan_options.idl
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_scan_options.idl
@@ -4,8 +4,5 @@
// https://w3c.github.io/web-nfc/#the-ndefscanoptions-dictionary
dictionary NDEFScanOptions {
- USVString id;
- USVString recordType;
- USVString mediaType;
AbortSignal? signal;
};
diff --git a/chromium/third_party/blink/renderer/modules/nfc/ndef_write_options.idl b/chromium/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
index 81fe17b1b31..4d7116a9c32 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
+++ b/chromium/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
@@ -5,7 +5,6 @@
// https://w3c.github.io/web-nfc/#the-ndefwriteoptions-dictionary
dictionary NDEFWriteOptions {
- boolean ignoreRead = true;
boolean overwrite = true;
AbortSignal? signal;
};
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
index 08001abdd79..2cf4c852dc3 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -49,14 +49,13 @@ void NFCProxy::Trace(Visitor* visitor) const {
}
void NFCProxy::StartReading(NDEFReader* reader,
- const NDEFScanOptions* options,
device::mojom::blink::NFC::WatchCallback callback) {
DCHECK(reader);
DCHECK(!readers_.Contains(reader));
EnsureMojoConnection();
nfc_remote_->Watch(
- device::mojom::blink::NDEFScanOptions::From(options), next_watch_id_,
+ next_watch_id_,
WTF::Bind(&NFCProxy::OnReaderRegistered, WrapPersistent(this),
WrapPersistent(reader), next_watch_id_, std::move(callback)));
readers_.insert(reader, next_watch_id_);
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h
index d9f6235498e..2054198e35c 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -17,7 +17,6 @@
namespace blink {
class LocalDOMWindow;
-class NDEFScanOptions;
class NDEFReader;
class NDEFWriter;
@@ -41,7 +40,6 @@ class MODULES_EXPORT NFCProxy final : public GarbageCollected<NFCProxy>,
void AddWriter(NDEFWriter*);
void StartReading(NDEFReader*,
- const NDEFScanOptions*,
device::mojom::blink::NFC::WatchCallback);
void StopReading(NDEFReader*);
bool IsReading(const NDEFReader*);
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
index a28a9c23cd0..da170255471 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
@@ -79,18 +79,8 @@ class FakeNfcService : public device::mojom::blink::NFC {
if (!client_ || !tag_message_)
return;
- // Only match the watches using |id| in options.
- WTF::Vector<uint32_t> ids;
- for (auto& pair : watches_) {
- if (pair.second->id == tag_message_->data[0]->id) {
- ids.push_back(pair.first);
- }
- }
-
- if (!ids.IsEmpty()) {
- client_->OnWatch(std::move(ids), kFakeNfcTagSerialNumber,
- tag_message_.Clone());
- }
+ client_->OnWatch(std::move(watchIDs_), kFakeNfcTagSerialNumber,
+ tag_message_.Clone());
}
void set_tag_message(device::mojom::blink::NDEFMessagePtr message) {
@@ -101,13 +91,7 @@ class FakeNfcService : public device::mojom::blink::NFC {
watch_error_ = std::move(error);
}
- WTF::Vector<uint32_t> GetWatches() {
- WTF::Vector<uint32_t> ids;
- for (auto& pair : watches_) {
- ids.push_back(pair.first);
- }
- return ids;
- }
+ WTF::Vector<uint32_t> GetWatches() { return watchIDs_; }
private:
// Override methods from device::mojom::blink::NFC.
@@ -124,33 +108,34 @@ class FakeNfcService : public device::mojom::blink::NFC {
void CancelPush(CancelPushCallback callback) override {
std::move(callback).Run(nullptr);
}
- void Watch(device::mojom::blink::NDEFScanOptionsPtr options,
- uint32_t id,
- WatchCallback callback) override {
+ void Watch(uint32_t id, WatchCallback callback) override {
if (watch_error_) {
std::move(callback).Run(watch_error_.Clone());
return;
}
- watches_.emplace(id, std::move(options));
+ if (watchIDs_.Find(id) == kNotFound)
+ watchIDs_.push_back(id);
std::move(callback).Run(nullptr);
}
void CancelWatch(uint32_t id, CancelWatchCallback callback) override {
- if (watches_.erase(id) < 1) {
+ size_t index = watchIDs_.Find(id);
+ if (index == kNotFound) {
std::move(callback).Run(device::mojom::blink::NDEFError::New(
device::mojom::blink::NDEFErrorType::NOT_FOUND, ""));
} else {
+ watchIDs_.EraseAt(index);
std::move(callback).Run(nullptr);
}
}
void CancelAllWatches(CancelAllWatchesCallback callback) override {
- watches_.clear();
+ watchIDs_.clear();
std::move(callback).Run(nullptr);
}
device::mojom::blink::NDEFErrorPtr watch_error_;
device::mojom::blink::NDEFMessagePtr tag_message_;
mojo::Remote<device::mojom::blink::NFCClient> client_;
- std::map<uint32_t, device::mojom::blink::NDEFScanOptionsPtr> watches_;
+ WTF::Vector<uint32_t> watchIDs_;
mojo::Receiver<device::mojom::blink::NFC> receiver_;
};
@@ -181,13 +166,11 @@ class NFCProxyTest : public PageTestBase {
TEST_F(NFCProxyTest, SuccessfulPath) {
auto* window = GetFrame().DomWindow();
auto* nfc_proxy = NFCProxy::From(*window);
- auto* scan_options = NDEFScanOptions::Create();
- scan_options->setId(kFakeRecordId);
auto* reader = MakeGarbageCollected<MockNDEFReader>(window);
{
base::RunLoop loop;
- nfc_proxy->StartReading(reader, scan_options,
+ nfc_proxy->StartReading(reader,
base::BindLambdaForTesting(
[&](device::mojom::blink::NDEFErrorPtr error) {
EXPECT_TRUE(error.is_null());
@@ -234,8 +217,6 @@ TEST_F(NFCProxyTest, SuccessfulPath) {
TEST_F(NFCProxyTest, ErrorPath) {
auto* window = GetFrame().DomWindow();
auto* nfc_proxy = NFCProxy::From(*window);
- auto* scan_options = NDEFScanOptions::Create();
- scan_options->setId(kFakeRecordId);
auto* reader = MakeGarbageCollected<MockNDEFReader>(window);
// Make the fake NFC service return an error for the incoming watch request.
@@ -243,7 +224,7 @@ TEST_F(NFCProxyTest, ErrorPath) {
device::mojom::blink::NDEFErrorType::NOT_READABLE, ""));
base::RunLoop loop;
nfc_proxy->StartReading(
- reader, scan_options,
+ reader,
base::BindLambdaForTesting([&](device::mojom::blink::NDEFErrorPtr error) {
// We got the error prepared before.
EXPECT_FALSE(error.is_null());
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
index 7587b5a46f5..b1d727b785c 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "services/device/public/mojom/nfc.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ndef_scan_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ndef_write_options.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/ndef_record.h"
@@ -19,8 +18,6 @@ using device::mojom::blink::NDEFMessage;
using device::mojom::blink::NDEFMessagePtr;
using device::mojom::blink::NDEFRecord;
using device::mojom::blink::NDEFRecordPtr;
-using device::mojom::blink::NDEFScanOptions;
-using device::mojom::blink::NDEFScanOptionsPtr;
using device::mojom::blink::NDEFWriteOptions;
using device::mojom::blink::NDEFWriteOptionsPtr;
@@ -57,35 +54,11 @@ TypeConverter<NDEFWriteOptionsPtr, const blink::NDEFWriteOptions*>::Convert(
const blink::NDEFWriteOptions* write_options) {
// https://w3c.github.io/web-nfc/#the-ndefwriteoptions-dictionary
// Default values for NDEFWriteOptions dictionary are:
- // ignoreRead = true, overwrite = true
+ // overwrite = true
NDEFWriteOptionsPtr write_options_ptr = NDEFWriteOptions::New();
- write_options_ptr->ignore_read = write_options->ignoreRead();
write_options_ptr->overwrite = write_options->overwrite();
return write_options_ptr;
}
-NDEFScanOptionsPtr
-TypeConverter<NDEFScanOptionsPtr, const blink::NDEFScanOptions*>::Convert(
- const blink::NDEFScanOptions* scan_options) {
- // https://w3c.github.io/web-nfc/#dom-ndefscanoptions
- // Default values for NDEFScanOptions dictionary are:
- // id = undefined, recordType = undefined, mediaType = undefined
- NDEFScanOptionsPtr scan_options_ptr = NDEFScanOptions::New();
-
- if (scan_options->hasId()) {
- scan_options_ptr->id = scan_options->id();
- }
-
- if (scan_options->hasRecordType()) {
- scan_options_ptr->record_type = scan_options->recordType();
- }
-
- if (scan_options->hasMediaType()) {
- scan_options_ptr->media_type = scan_options->mediaType();
- }
-
- return scan_options_ptr;
-}
-
} // namespace mojo
diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.h b/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.h
index 1343c151f89..55fd828d440 100644
--- a/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.h
+++ b/chromium/third_party/blink/renderer/modules/nfc/nfc_type_converters.h
@@ -13,7 +13,6 @@ namespace blink {
class NDEFRecord;
class NDEFMessage;
-class NDEFScanOptions;
class NDEFWriteOptions;
} // namespace blink
@@ -41,13 +40,6 @@ struct TypeConverter<device::mojom::blink::NDEFWriteOptionsPtr,
const ::blink::NDEFWriteOptions* writeOptions);
};
-template <>
-struct TypeConverter<device::mojom::blink::NDEFScanOptionsPtr,
- const ::blink::NDEFScanOptions*> {
- static device::mojom::blink::NDEFScanOptionsPtr Convert(
- const ::blink::NDEFScanOptions* scanOptions);
-};
-
} // namespace mojo
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_TYPE_CONVERTERS_H_
diff --git a/chromium/third_party/blink/renderer/modules/notifications/BUILD.gn b/chromium/third_party/blink/renderer/modules/notifications/BUILD.gn
index 390bfc01939..73c901cd8da 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/notifications/BUILD.gn
@@ -25,7 +25,6 @@ blink_modules_sources("notifications") {
deps = [
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
"//third_party/blink/renderer/modules/permissions",
- "//third_party/blink/renderer/modules/service_worker",
"//third_party/blink/renderer/modules/vibration",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc
index edbec7abc11..d9266ca9251 100644
--- a/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc
@@ -14,6 +14,7 @@
#include "third_party/blink/public/mojom/permissions/permission_status.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/modules/v8/v8_notification_permission.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -102,8 +103,14 @@ void NotificationManager::OnPermissionRequestComplete(
V8NotificationPermissionCallback* deprecated_callback,
mojom::blink::PermissionStatus status) {
String status_string = Notification::PermissionString(status);
- if (deprecated_callback)
+ if (deprecated_callback) {
+#if defined(USE_BLINK_V8_BINDING_NEW_IDL_CALLBACK_FUNCTION)
+ deprecated_callback->InvokeAndReportException(
+ nullptr, V8NotificationPermission::Create(status_string).value());
+#else
deprecated_callback->InvokeAndReportException(nullptr, status_string);
+#endif
+ }
resolver->Resolve(status_string);
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/BUILD.gn b/chromium/third_party/blink/renderer/modules/payments/BUILD.gn
index 5869e43e7d4..74202d8f407 100644
--- a/chromium/third_party/blink/renderer/modules/payments/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/payments/BUILD.gn
@@ -70,6 +70,5 @@ blink_modules_sources("payments") {
"//components/payments/mojom:mojom_blink",
"//third_party/blink/renderer/modules/credentialmanager",
"//third_party/blink/renderer/modules/permissions",
- "//third_party/blink/renderer/modules/service_worker",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.cc b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.cc
index 2e716071750..fe37b3569e0 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.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 <utility>
+
#include "third_party/blink/renderer/modules/payments/goods/digital_goods_service.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -43,9 +45,10 @@ void OnAcknowledgeResponse(ScriptPromiseResolver* resolver,
} // namespace
-DigitalGoodsService::DigitalGoodsService(ExecutionContext* context) {
- context->GetBrowserInterfaceBroker().GetInterface(
- mojo_service_.BindNewPipeAndPassReceiver());
+DigitalGoodsService::DigitalGoodsService(
+ mojo::PendingRemote<payments::mojom::blink::DigitalGoods> pending_remote) {
+ DCHECK(pending_remote.is_valid());
+ mojo_service_.Bind(std::move(pending_remote));
DCHECK(mojo_service_);
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h
index 6bcd76ff2d8..5835df839ef 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h
@@ -11,7 +11,6 @@
namespace blink {
-class ExecutionContext;
class ScriptState;
class Visitor;
@@ -19,7 +18,8 @@ class DigitalGoodsService final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit DigitalGoodsService(ExecutionContext* context);
+ explicit DigitalGoodsService(
+ mojo::PendingRemote<payments::mojom::blink::DigitalGoods> pending_remote);
~DigitalGoodsService() override;
// IDL Interface:
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc
index 7ad468c3cdc..aa993cc2b5e 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc
@@ -9,9 +9,11 @@
namespace mojo {
-blink::ItemDetails*
-TypeConverter<blink::ItemDetails*, payments::mojom::blink::ItemDetailsPtr>::
- Convert(const payments::mojom::blink::ItemDetailsPtr& input) {
+using payments::mojom::blink::BillingResponseCode;
+using payments::mojom::blink::ItemDetailsPtr;
+
+blink::ItemDetails* TypeConverter<blink::ItemDetails*, ItemDetailsPtr>::Convert(
+ const ItemDetailsPtr& input) {
if (!input)
return nullptr;
blink::ItemDetails* output = blink::ItemDetails::Create();
@@ -23,26 +25,24 @@ TypeConverter<blink::ItemDetails*, payments::mojom::blink::ItemDetailsPtr>::
return output;
}
-WTF::String
-TypeConverter<WTF::String, payments::mojom::blink::BillingResponseCode>::
- Convert(const payments::mojom::blink::BillingResponseCode& input) {
+WTF::String TypeConverter<WTF::String, BillingResponseCode>::Convert(
+ const BillingResponseCode& input) {
switch (input) {
- case payments::mojom::blink::BillingResponseCode::kOk:
+ case BillingResponseCode::kOk:
return "ok";
- case payments::mojom::blink::BillingResponseCode::kError:
+ case BillingResponseCode::kError:
return "error";
- case payments::mojom::blink::BillingResponseCode::kItemAlreadyOwned:
+ case BillingResponseCode::kItemAlreadyOwned:
return "itemAlreadyOwned";
- case payments::mojom::blink::BillingResponseCode::kItemNotOwned:
+ case BillingResponseCode::kItemNotOwned:
return "itemNotOwned";
- case payments::mojom::blink::BillingResponseCode::kItemUnavailable:
+ case BillingResponseCode::kItemUnavailable:
return "itemUnavailable";
- case payments::mojom::blink::BillingResponseCode::kClientAppUnavailable:
+ case BillingResponseCode::kClientAppUnavailable:
return "clientAppUnavailable";
- case payments::mojom::blink::BillingResponseCode::kClientAppError:
+ case BillingResponseCode::kClientAppError:
return "clientAppError";
}
-
NOTREACHED();
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc b/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
index ffefb587674..0beb502e489 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
@@ -4,17 +4,39 @@
#include "third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h"
+#include <utility>
+
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/payments/goods/digital_goods_service.h"
+namespace blink {
+
namespace {
+using payments::mojom::blink::CreateDigitalGoodsResponseCode;
+
const char known_payment_method_[] = "https://play.google.com/billing";
-} // namespace
+void OnCreateDigitalGoodsResponse(
+ ScriptPromiseResolver* resolver,
+ CreateDigitalGoodsResponseCode code,
+ mojo::PendingRemote<payments::mojom::blink::DigitalGoods> pending_remote) {
+ if (code != CreateDigitalGoodsResponseCode::kOk) {
+ DCHECK(!pending_remote);
+ DVLOG(1) << "CreateDigitalGoodsResponseCode " << code;
+ resolver->Resolve();
+ return;
+ }
+ DCHECK(pending_remote);
-namespace blink {
+ auto* digital_goods_service_ =
+ MakeGarbageCollected<DigitalGoodsService>(std::move(pending_remote));
+ resolver->Resolve(digital_goods_service_);
+}
+
+} // namespace
const char DOMWindowDigitalGoods::kSupplementName[] = "DOMWindowDigitalGoods";
@@ -32,26 +54,31 @@ ScriptPromise DOMWindowDigitalGoods::GetDigitalGoodsService(
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
auto promise = resolver->Promise();
- // TODO (crbug.com/1061503): Enable JS to connect to various payment method
- // backends. For now, just connect to one known backend and check the URL is
- // correct for that payment method.
+ if (payment_method.IsEmpty()) {
+ resolver->Resolve();
+ return promise;
+ }
if (payment_method != known_payment_method_) {
resolver->Resolve();
return promise;
}
- if (!digital_goods_service_) {
- digital_goods_service_ = MakeGarbageCollected<DigitalGoodsService>(
- ExecutionContext::From(script_state));
+ // TODO: Bind only on platforms where an implementation exists.
+ if (!mojo_service_) {
+ ExecutionContext::From(script_state)
+ ->GetBrowserInterfaceBroker()
+ .GetInterface(mojo_service_.BindNewPipeAndPassReceiver());
}
- resolver->Resolve(digital_goods_service_);
+ mojo_service_->CreateDigitalGoods(
+ payment_method,
+ WTF::Bind(&OnCreateDigitalGoodsResponse, WrapPersistent(resolver)));
+
return promise;
}
void DOMWindowDigitalGoods::Trace(Visitor* visitor) const {
Supplement<LocalDOMWindow>::Trace(visitor);
- visitor->Trace(digital_goods_service_);
}
// static
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h b/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h
index a62df92f226..c1c276606bf 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h
@@ -5,12 +5,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DOM_WINDOW_DIGITAL_GOODS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DOM_WINDOW_DIGITAL_GOODS_H_
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
-class DigitalGoodsService;
class LocalDOMWindow;
class ScriptState;
class Visitor;
@@ -31,7 +32,7 @@ class DOMWindowDigitalGoods final
void Trace(Visitor* visitor) const override;
private:
- Member<DigitalGoodsService> digital_goods_service_;
+ mojo::Remote<payments::mojom::blink::DigitalGoodsFactory> mojo_service_;
static DOMWindowDigitalGoods* FromState(LocalDOMWindow*);
};
diff --git a/chromium/third_party/blink/renderer/modules/payments/goods/item_details.idl b/chromium/third_party/blink/renderer/modules/payments/goods/item_details.idl
index 4393374ebaa..0f81e7dc17d 100644
--- a/chromium/third_party/blink/renderer/modules/payments/goods/item_details.idl
+++ b/chromium/third_party/blink/renderer/modules/payments/goods/item_details.idl
@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// TODO(crbug.com/1061503): Add more fields from
// https://github.com/WICG/digital-goods/blob/master/explainer.md
-// as the discussions settle.
dictionary ItemDetails {
DOMString itemId;
DOMString title;
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 b0975c59ddb..160331ab66f 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -419,8 +419,8 @@ void StringifyAndParseMethodSpecificData(ExecutionContext& execution_context,
PaymentMethodDataPtr& output,
ExceptionState& exception_state) {
PaymentsValidators::ValidateAndStringifyObject(
- execution_context.GetIsolate(), "Payment method data", input,
- output->stringified_data, exception_state);
+ execution_context.GetIsolate(), input, output->stringified_data,
+ exception_state);
if (exception_state.HadException())
return;
@@ -634,9 +634,7 @@ void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate* input,
if (input->hasPaymentMethodErrors()) {
PaymentsValidators::ValidateAndStringifyObject(
- execution_context.GetIsolate(), "Payment method errors",
- input->paymentMethodErrors(),
-
+ execution_context.GetIsolate(), input->paymentMethodErrors(),
output->stringified_payment_method_errors, exception_state);
}
}
@@ -795,6 +793,13 @@ ScriptPromise PaymentRequest::show(ScriptState* script_state,
return ScriptPromise();
}
+ if (!not_supported_for_invalid_origin_or_ssl_error_.IsEmpty()) {
+ return ScriptPromise::RejectWithDOMException(
+ script_state, MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kNotSupportedError,
+ not_supported_for_invalid_origin_or_ssl_error_));
+ }
+
if (!payment_provider_.is_bound() || accept_resolver_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Already called show() once");
@@ -878,6 +883,11 @@ ScriptPromise PaymentRequest::abort(ScriptState* script_state,
ScriptPromise PaymentRequest::canMakePayment(ScriptState* script_state,
ExceptionState& exception_state) {
+ if (!not_supported_for_invalid_origin_or_ssl_error_.IsEmpty()) {
+ return ScriptPromise::Cast(script_state,
+ ScriptValue::From(script_state, false));
+ }
+
if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
can_make_payment_resolver_ || !script_state->ContextIsValid()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
@@ -895,6 +905,11 @@ ScriptPromise PaymentRequest::canMakePayment(ScriptState* script_state,
ScriptPromise PaymentRequest::hasEnrolledInstrument(
ScriptState* script_state,
ExceptionState& exception_state) {
+ if (!not_supported_for_invalid_origin_or_ssl_error_.IsEmpty()) {
+ return ScriptPromise::Cast(script_state,
+ ScriptValue::From(script_state, false));
+ }
+
if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
has_enrolled_instrument_resolver_ || !script_state->ContextIsValid()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
@@ -910,7 +925,9 @@ ScriptPromise PaymentRequest::hasEnrolledInstrument(
}
bool PaymentRequest::HasPendingActivity() const {
- return GetPendingAcceptPromiseResolver() || complete_resolver_;
+ return accept_resolver_ || retry_resolver_ || complete_resolver_ ||
+ has_enrolled_instrument_resolver_ || can_make_payment_resolver_ ||
+ abort_resolver_;
}
const AtomicString& PaymentRequest::InterfaceName() const {
@@ -1181,7 +1198,11 @@ PaymentRequest::PaymentRequest(
this,
&PaymentRequest::OnUpdatePaymentDetailsTimeout),
is_waiting_for_show_promise_to_resolve_(false) {
+ // options_, details has default value, so could never be null, according to
+ // payment_request.idl.
+ DCHECK(options_);
DCHECK(details);
+
DCHECK(GetExecutionContext()->IsSecureContext());
if (!AllowedToUsePaymentRequest(execution_context)) {
exception_state.ThrowSecurityError(
@@ -1470,7 +1491,12 @@ void PaymentRequest::OnError(PaymentErrorReason error,
break;
case PaymentErrorReason::NOT_SUPPORTED:
+ exception_code = exception_code = DOMExceptionCode::kNotSupportedError;
+ break;
+
+ case PaymentErrorReason::NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL:
exception_code = DOMExceptionCode::kNotSupportedError;
+ not_supported_for_invalid_origin_or_ssl_error_ = error_message;
break;
case PaymentErrorReason::ALREADY_SHOWING:
@@ -1502,13 +1528,21 @@ void PaymentRequest::OnError(PaymentErrorReason error,
}
if (can_make_payment_resolver_) {
- can_make_payment_resolver_->Reject(
- MakeGarbageCollected<DOMException>(exception_code, error_message));
+ if (!not_supported_for_invalid_origin_or_ssl_error_.IsEmpty()) {
+ can_make_payment_resolver_->Reject(false);
+ } else {
+ can_make_payment_resolver_->Reject(
+ MakeGarbageCollected<DOMException>(exception_code, error_message));
+ }
}
if (has_enrolled_instrument_resolver_) {
- has_enrolled_instrument_resolver_->Reject(
- MakeGarbageCollected<DOMException>(exception_code, error_message));
+ if (!not_supported_for_invalid_origin_or_ssl_error_.IsEmpty()) {
+ has_enrolled_instrument_resolver_->Reject(false);
+ } else {
+ has_enrolled_instrument_resolver_->Reject(
+ MakeGarbageCollected<DOMException>(exception_code, error_message));
+ }
}
ClearResolversAndCloseMojoConnection();
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 0ed3b538f68..161a776c4ad 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.h
@@ -168,12 +168,18 @@ class MODULES_EXPORT PaymentRequest final
String shipping_option_;
String shipping_type_;
HashSet<String> method_names_;
- Member<ScriptPromiseResolver> accept_resolver_;
+ Member<ScriptPromiseResolver>
+ accept_resolver_; // the resolver for the show() promise.
Member<ScriptPromiseResolver> complete_resolver_;
Member<ScriptPromiseResolver> retry_resolver_;
Member<ScriptPromiseResolver> abort_resolver_;
Member<ScriptPromiseResolver> can_make_payment_resolver_;
Member<ScriptPromiseResolver> has_enrolled_instrument_resolver_;
+
+ // When not null, reject show(), resolve canMakePayment() and
+ // hasEnrolledInstrument() with false.
+ String not_supported_for_invalid_origin_or_ssl_error_;
+
HeapMojoRemote<payments::mojom::blink::PaymentRequest> payment_provider_;
HeapMojoReceiver<payments::mojom::blink::PaymentRequestClient, PaymentRequest>
client_receiver_;
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc
index cbae9d8436b..a76e0ea88ff 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc
@@ -208,7 +208,7 @@ ScriptPromise PaymentRequestEvent::changePaymentMethod(
if (!method_details.IsNull()) {
DCHECK(!method_details.IsEmpty());
PaymentsValidators::ValidateAndStringifyObject(
- script_state->GetIsolate(), "Method details", method_details,
+ script_state->GetIsolate(), method_details,
method_data->stringified_data, exception_state);
if (exception_state.HadException())
return ScriptPromise();
diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
new file mode 100644
index 00000000000..e0789ff4cd4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
@@ -0,0 +1,203 @@
+// Copyright 2020 The Chromium Authors. 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/mojom/payments/payment_request.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/modules/payments/payment_request.h"
+#include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
+#include "third_party/blink/renderer/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
+
+namespace blink {
+namespace {
+
+class MockPaymentProvider : public payments::mojom::blink::PaymentRequest {
+ public:
+ void Init(
+ mojo::PendingRemote<payments::mojom::blink::PaymentRequestClient> client,
+ WTF::Vector<payments::mojom::blink::PaymentMethodDataPtr> method_data,
+ payments::mojom::blink::PaymentDetailsPtr details,
+ payments::mojom::blink::PaymentOptionsPtr options
+#if defined(OS_ANDROID)
+ ,
+ bool google_pay_bridge_eligible
+#endif
+ ) override {
+ client_.Bind(std::move(client));
+ client_->OnError(payments::mojom::PaymentErrorReason::
+ NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL,
+ "mock error message");
+ has_closed_ = true;
+ }
+
+ void Show(bool is_user_gesture, bool wait_for_updated_details) override {}
+ void Retry(
+ payments::mojom::blink::PaymentValidationErrorsPtr errors) override {
+ NOTREACHED();
+ }
+ void UpdateWith(
+ payments::mojom::blink::PaymentDetailsPtr update_with_details) override {
+ NOTREACHED();
+ }
+ void OnPaymentDetailsNotUpdated() override { NOTREACHED(); }
+ void Abort() override { NOTREACHED(); }
+ void Complete(payments::mojom::PaymentComplete result) override {
+ NOTREACHED();
+ }
+ void CanMakePayment() override {}
+ void HasEnrolledInstrument() override {}
+
+ mojo::PendingRemote<payments::mojom::blink::PaymentRequest>
+ CreatePendingRemoteAndBind() {
+ mojo::PendingRemote<payments::mojom::blink::PaymentRequest> remote;
+ receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
+ return remote;
+ }
+
+ private:
+ mojo::Receiver<payments::mojom::blink::PaymentRequest> receiver_{this};
+ mojo::Remote<payments::mojom::blink::PaymentRequestClient> client_;
+ bool has_closed_ = false;
+};
+
+// This tests PaymentRequest API on invalid origin or invalid ssl.
+class PaymentRequestForInvalidOriginOrSslTest : public testing::Test {
+ public:
+ PaymentRequestForInvalidOriginOrSslTest()
+ : payment_provider_(std::make_unique<MockPaymentProvider>()) {}
+
+ ScriptValue GetRejectValue(ScriptState* script_state,
+ ScriptPromise& promise) {
+ ScriptPromiseTester tester(script_state, promise);
+ tester.WaitUntilSettled();
+ EXPECT_TRUE(tester.IsRejected());
+ return tester.Value();
+ }
+
+ bool ResolvePromise(ScriptState* script_state, ScriptPromise& promise) {
+ ScriptPromiseTester tester(script_state, promise);
+ tester.WaitUntilSettled();
+ return tester.Value().V8Value()->IsTrue();
+ }
+
+ std::string GetRejectString(ScriptState* script_state,
+ ScriptPromise& promise) {
+ ScriptValue on_reject = GetRejectValue(script_state, promise);
+ return ToCoreString(on_reject.V8Value()
+ ->ToString(script_state->GetContext())
+ .ToLocalChecked())
+ .Ascii()
+ .data();
+ }
+
+ PaymentRequest* CreatePaymentRequest(PaymentRequestV8TestingScope& scope) {
+ return MakeGarbageCollected<PaymentRequest>(
+ scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+ BuildPaymentDetailsInitForTest(), PaymentOptions::Create(),
+ payment_provider_->CreatePendingRemoteAndBind(), ASSERT_NO_EXCEPTION);
+ }
+
+ std::unique_ptr<MockPaymentProvider> payment_provider_;
+ ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
+};
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ ShowIsRejected_WhenShowBeforeIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ ScriptPromise promise =
+ request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ EXPECT_EQ("NotSupportedError: mock error message",
+ GetRejectString(scope.GetScriptState(), promise));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ ShowIsRejected_WhenShowAfterIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ ScriptPromise promise =
+ request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ EXPECT_EQ("NotSupportedError: mock error message",
+ GetRejectString(scope.GetScriptState(), promise));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ SelfRejectingPromiseCanBeRepeated) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ ScriptPromise promise1 =
+ request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ EXPECT_EQ("NotSupportedError: mock error message",
+ GetRejectString(scope.GetScriptState(), promise1));
+
+ ScriptPromise promise2 =
+ request->show(scope.GetScriptState(), scope.GetExceptionState());
+ EXPECT_EQ("NotSupportedError: mock error message",
+ GetRejectString(scope.GetScriptState(), promise2));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ CanMakePaymentIsRejected_CheckAfterIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ ScriptPromise promise =
+ request->canMakePayment(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ EXPECT_FALSE(ResolvePromise(scope.GetScriptState(), promise));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ CanMakePaymentIsRejected_CheckBeforeIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ ScriptPromise promise =
+ request->canMakePayment(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ EXPECT_FALSE(ResolvePromise(scope.GetScriptState(), promise));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ HasEnrolledInstrument_CheckAfterIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ ScriptPromise promise = request->hasEnrolledInstrument(scope.GetScriptState(),
+ ASSERT_NO_EXCEPTION);
+ EXPECT_FALSE(ResolvePromise(scope.GetScriptState(), promise));
+}
+
+TEST_F(PaymentRequestForInvalidOriginOrSslTest,
+ HasEnrolledInstrument_CheckBeforeIdle) {
+ PaymentRequestV8TestingScope scope;
+ PaymentRequest* request = CreatePaymentRequest(scope);
+ ScriptPromise promise = request->hasEnrolledInstrument(scope.GetScriptState(),
+ ASSERT_NO_EXCEPTION);
+ // PaymentRequest.OnError() runs in this idle.
+ platform_->RunUntilIdle();
+
+ EXPECT_FALSE(ResolvePromise(scope.GetScriptState(), promise));
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc b/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc
index e103eea6449..9890e206010 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc
+++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc
@@ -177,7 +177,6 @@ bool PaymentsValidators::IsValidMethodFormat(const String& identifier) {
void PaymentsValidators::ValidateAndStringifyObject(
v8::Isolate* isolate,
- const String& input_name,
const ScriptValue& input,
String& output,
ExceptionState& exception_state) {
@@ -186,8 +185,8 @@ void PaymentsValidators::ValidateAndStringifyObject(
!v8::JSON::Stringify(isolate->GetCurrentContext(),
input.V8Value().As<v8::Object>())
.ToLocal(&value)) {
- exception_state.ThrowTypeError(input_name +
- " should be a JSON-serializable object");
+ exception_state.ThrowTypeError(
+ "PaymentRequest objects should be JSON-serializable objects");
return;
}
@@ -197,9 +196,10 @@ void PaymentsValidators::ValidateAndStringifyObject(
static constexpr size_t kMaxJSONStringLength = 1024 * 1024;
if (output.length() > kMaxJSONStringLength) {
- exception_state.ThrowTypeError(String::Format(
- "JSON serialization of %s should be no longer than %zu characters",
- input_name.Characters8(), kMaxJSONStringLength));
+ exception_state.ThrowTypeError(
+ String::Format("JSON serialization of PaymentRequest objects should be "
+ "no longer than %zu characters",
+ kMaxJSONStringLength));
}
}
diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators.h b/chromium/third_party/blink/renderer/modules/payments/payments_validators.h
index b13ffbd4c97..18d0a483e15 100644
--- a/chromium/third_party/blink/renderer/modules/payments/payments_validators.h
+++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators.h
@@ -70,10 +70,9 @@ class MODULES_EXPORT PaymentsValidators final {
//
// If the |input| is valid, the JSON serialization is saved in |output|.
//
- // If the |input| is invalid, throws a TypeError through the |exception_state|
- // and uses the |input_name| to better describe what was being validated.
+ // If the |input| is invalid, throws a TypeError through the
+ // |exception_state|.
static void ValidateAndStringifyObject(v8::Isolate* isolate,
- const String& input_name,
const ScriptValue& input,
String& output,
ExceptionState& exception_state);
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 fb0b6e262ed..4f234cb46c8 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
@@ -26,6 +26,7 @@ P2PQuicStreamImpl::P2PQuicStreamImpl(quic::PendingStream* pending,
uint32_t delegate_read_buffer_size,
uint32_t write_buffer_size)
: quic::QuicStream(pending,
+ session,
quic::BIDIRECTIONAL,
/*is_static=*/false),
delegate_read_buffer_size_(delegate_read_buffer_size),
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 c6e370c2444..844c5bbe38b 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
@@ -225,8 +225,8 @@ TEST_F(P2PQuicStreamTest, StreamClosedAfterReceivingReset) {
// send to close the other direction.
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(kStreamId, testing::_));
- quic::QuicStopSendingFrame stop_sending_frame(quic::kInvalidControlFrameId,
- kStreamId, 0);
+ quic::QuicStopSendingFrame stop_sending_frame(
+ quic::kInvalidControlFrameId, kStreamId, quic::QUIC_STREAM_NO_ERROR);
session_->OnStopSendingFrame(stop_sending_frame);
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
index d83906e4896..2f931fc72f6 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -258,6 +258,15 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame(
elapsed_timestamp);
break;
}
+ case webrtc::VideoFrameBuffer::Type::kNV12: {
+ const webrtc::NV12BufferInterface* nv12_buffer = buffer->GetNV12();
+ video_frame = media::VideoFrame::WrapExternalYuvData(
+ media::PIXEL_FORMAT_NV12, size, gfx::Rect(size), size,
+ nv12_buffer->StrideY(), nv12_buffer->StrideUV(),
+ const_cast<uint8_t*>(nv12_buffer->DataY()),
+ const_cast<uint8_t*>(nv12_buffer->DataUV()), elapsed_timestamp);
+ break;
+ }
default:
NOTREACHED();
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.cc b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.cc
index 767bcbe201e..03d237f0ef3 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.cc
@@ -16,12 +16,9 @@ MockRTCPeerConnectionHandlerClient::MockRTCPeerConnectionHandlerClient() {
.WillByDefault(testing::Invoke(
this,
&MockRTCPeerConnectionHandlerClient::didGenerateICECandidateWorker));
- ON_CALL(*this, DidAddReceiverPlanBForMock(_))
+ ON_CALL(*this, DidModifyReceiversPlanBForMock(_, _, _))
.WillByDefault(testing::Invoke(
- this, &MockRTCPeerConnectionHandlerClient::didAddReceiverWorker));
- ON_CALL(*this, DidRemoveReceiverPlanBForMock(_))
- .WillByDefault(testing::Invoke(
- this, &MockRTCPeerConnectionHandlerClient::didRemoveReceiverWorker));
+ this, &MockRTCPeerConnectionHandlerClient::didModifyReceiversWorker));
}
MockRTCPeerConnectionHandlerClient::~MockRTCPeerConnectionHandlerClient() {}
@@ -33,16 +30,19 @@ void MockRTCPeerConnectionHandlerClient::didGenerateICECandidateWorker(
candidate_mid_ = candidate->SdpMid().Utf8();
}
-void MockRTCPeerConnectionHandlerClient::didAddReceiverWorker(
- std::unique_ptr<RTCRtpReceiverPlatform>* web_rtp_receiver) {
- WebVector<String> stream_ids = (*web_rtp_receiver)->StreamIds();
- DCHECK_EQ(1u, stream_ids.size());
- remote_stream_id_ = stream_ids[0];
-}
-
-void MockRTCPeerConnectionHandlerClient::didRemoveReceiverWorker(
- std::unique_ptr<RTCRtpReceiverPlatform>* web_rtp_receiver) {
- remote_stream_id_ = String();
+void MockRTCPeerConnectionHandlerClient::didModifyReceiversWorker(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>* receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>* receivers_removed) {
+ // This fake implication is very limited. It is only used as a sanity check
+ // if a stream was added or removed.
+ if (!receivers_added->IsEmpty()) {
+ WebVector<String> stream_ids = (*receivers_added)[0]->StreamIds();
+ DCHECK_EQ(1u, stream_ids.size());
+ remote_stream_id_ = stream_ids[0];
+ } else if (receivers_removed->IsEmpty()) {
+ remote_stream_id_ = String();
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
index 7bced30af63..be0643312e0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
@@ -35,8 +35,11 @@ class MockRTCPeerConnectionHandlerClient
const String& url,
int error_code,
const String& error_text));
- MOCK_METHOD1(DidChangeSignalingState,
- void(webrtc::PeerConnectionInterface::SignalingState state));
+ MOCK_METHOD4(DidChangeSessionDescriptions,
+ void(RTCSessionDescriptionPlatform*,
+ RTCSessionDescriptionPlatform*,
+ RTCSessionDescriptionPlatform*,
+ RTCSessionDescriptionPlatform*));
MOCK_METHOD1(DidChangeIceGatheringState,
void(webrtc::PeerConnectionInterface::IceGatheringState state));
MOCK_METHOD1(DidChangeIceConnectionState,
@@ -44,21 +47,23 @@ class MockRTCPeerConnectionHandlerClient
MOCK_METHOD1(
DidChangePeerConnectionState,
void(webrtc::PeerConnectionInterface::PeerConnectionState state));
- void DidAddReceiverPlanB(
- std::unique_ptr<RTCRtpReceiverPlatform> web_rtp_receiver) override {
- DidAddReceiverPlanBForMock(&web_rtp_receiver);
- }
- void DidRemoveReceiverPlanB(
- std::unique_ptr<RTCRtpReceiverPlatform> web_rtp_receiver) override {
- DidRemoveReceiverPlanBForMock(&web_rtp_receiver);
+ void DidModifyReceiversPlanB(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> receivers_removed)
+ override {
+ DidModifyReceiversPlanBForMock(signaling_state, &receivers_added,
+ &receivers_removed);
}
MOCK_METHOD1(DidModifySctpTransport,
void(blink::WebRTCSctpTransportSnapshot snapshot));
void DidModifyTransceivers(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
Vector<std::unique_ptr<RTCRtpTransceiverPlatform>> platform_transceivers,
Vector<uintptr_t> removed_transceivers,
bool is_remote_description) override {
- DidModifyTransceiversForMock(&platform_transceivers, is_remote_description);
+ DidModifyTransceiversForMock(signaling_state, &platform_transceivers,
+ is_remote_description);
}
MOCK_METHOD1(DidAddRemoteDataChannel,
void(scoped_refptr<webrtc::DataChannelInterface>));
@@ -67,18 +72,20 @@ class MockRTCPeerConnectionHandlerClient
// Move-only arguments do not play nicely with MOCK, the workaround is to
// EXPECT_CALL with these instead.
- MOCK_METHOD1(DidAddReceiverPlanBForMock,
- void(std::unique_ptr<RTCRtpReceiverPlatform>*));
- MOCK_METHOD1(DidRemoveReceiverPlanBForMock,
- void(std::unique_ptr<RTCRtpReceiverPlatform>*));
- MOCK_METHOD2(DidModifyTransceiversForMock,
- void(Vector<std::unique_ptr<RTCRtpTransceiverPlatform>>*, bool));
+ MOCK_METHOD3(DidModifyReceiversPlanBForMock,
+ void(webrtc::PeerConnectionInterface::SignalingState,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>*,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>*));
+ MOCK_METHOD3(DidModifyTransceiversForMock,
+ void(webrtc::PeerConnectionInterface::SignalingState,
+ Vector<std::unique_ptr<RTCRtpTransceiverPlatform>>*,
+ bool));
void didGenerateICECandidateWorker(RTCIceCandidatePlatform* candidate);
- void didAddReceiverWorker(
- std::unique_ptr<RTCRtpReceiverPlatform>* stream_web_rtp_receivers);
- void didRemoveReceiverWorker(
- std::unique_ptr<RTCRtpReceiverPlatform>* stream_web_rtp_receivers);
+ void didModifyReceiversWorker(
+ webrtc::PeerConnectionInterface::SignalingState,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>* receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>* receivers_removed);
const std::string& candidate_sdp() const { return candidate_sdp_; }
const base::Optional<uint16_t>& candidate_mlineindex() const {
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
index 5437abb2895..da6d4bb9522 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
@@ -286,36 +286,6 @@ void MockRTCPeerConnectionHandlerPlatform::SetRemoteDescription(
RTCVoidRequest*,
RTCSessionDescriptionPlatform*) {}
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::LocalDescription() {
- return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::RemoteDescription() {
- return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::CurrentLocalDescription() {
- return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::CurrentRemoteDescription() {
- return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::PendingLocalDescription() {
- return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::PendingRemoteDescription() {
- return nullptr;
-}
-
const webrtc::PeerConnectionInterface::RTCConfiguration&
MockRTCPeerConnectionHandlerPlatform::GetConfiguration() const {
static const webrtc::PeerConnectionInterface::RTCConfiguration configuration;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
index 71fadfd1cf6..1a9cb0ff6e0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
@@ -48,12 +48,6 @@ class MockRTCPeerConnectionHandlerPlatform : public RTCPeerConnectionHandler {
RTCSessionDescriptionPlatform*) override;
void SetRemoteDescription(RTCVoidRequest*,
RTCSessionDescriptionPlatform*) override;
- RTCSessionDescriptionPlatform* LocalDescription() override;
- RTCSessionDescriptionPlatform* RemoteDescription() override;
- RTCSessionDescriptionPlatform* CurrentLocalDescription() override;
- RTCSessionDescriptionPlatform* CurrentRemoteDescription() override;
- RTCSessionDescriptionPlatform* PendingLocalDescription() override;
- RTCSessionDescriptionPlatform* PendingRemoteDescription() override;
const webrtc::PeerConnectionInterface::RTCConfiguration& GetConfiguration()
const override;
webrtc::RTCErrorType SetConfiguration(
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
index ea3c51fe386..602abb74abe 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -31,6 +31,7 @@
#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.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_local_frame_client.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h"
#include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h"
#include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
@@ -56,6 +57,7 @@
#include "third_party/webrtc/media/engine/webrtc_media_engine.h"
#include "third_party/webrtc/modules/audio_processing/include/audio_processing.h"
#include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h"
+#include "third_party/webrtc/rtc_base/openssl_stream_adapter.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
#include "third_party/webrtc/rtc_base/ssl_adapter.h"
#include "third_party/webrtc_overrides/task_queue_factory.h"
@@ -349,6 +351,8 @@ PeerConnectionDependencyFactory::CreatePeerConnection(
if (!GetPcFactory().get())
return nullptr;
+ rtc::SetAllowLegacyTLSProtocols(
+ web_frame->Client()->AllowRTCLegacyTLSProtocols());
webrtc::PeerConnectionDependencies dependencies(observer);
dependencies.allocator = CreatePortAllocator(web_frame);
dependencies.async_resolver_factory = CreateAsyncResolverFactory();
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
index 2c41f1c1499..b9105fa3366 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "base/power_monitor/power_observer.h"
+#include "base/stl_util.h"
#include "base/values.h"
#include "third_party/blink/public/common/peerconnection/peer_connection_tracker_mojom_traits.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
@@ -702,9 +703,20 @@ void PeerConnectionTracker::Bind(
void PeerConnectionTracker::OnSuspend() {
DCHECK_CALLED_ON_VALID_THREAD(main_thread_);
- for (auto it = peer_connection_local_id_map_.begin();
- it != peer_connection_local_id_map_.end(); ++it) {
- it->key->CloseClientPeerConnection();
+ // Closing peer connections fires events. If JavaScript triggers the creation
+ // or garbage collection of more peer connections, this would invalidate the
+ // |peer_connection_local_id_map_| iterator. Therefor we iterate on a copy.
+ PeerConnectionLocalIdMap peer_connection_map_copy =
+ peer_connection_local_id_map_;
+ for (const auto& pair : peer_connection_map_copy) {
+ RTCPeerConnectionHandler* peer_connection_handler = pair.key;
+ if (!base::Contains(peer_connection_local_id_map_,
+ peer_connection_handler)) {
+ // Skip peer connections that have been unregistered during this method
+ // call. Avoids use-after-free.
+ continue;
+ }
+ peer_connection_handler->CloseClientPeerConnection();
}
}
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 b74fa162ae0..b05262d0b4d 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
@@ -29,11 +29,14 @@
#include <string>
#include <utility>
+#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/events/message_event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
@@ -42,6 +45,7 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
@@ -459,6 +463,7 @@ void RTCDataChannel::ContextDestroyed() {
Dispose();
stopped_ = true;
state_ = webrtc::DataChannelInterface::kClosed;
+ feature_handle_for_scheduler_.reset();
}
// ActiveScriptWrappable
@@ -507,8 +512,10 @@ void RTCDataChannel::Trace(Visitor* visitor) const {
}
void RTCDataChannel::SetStateToOpenWithoutEvent() {
+ DCHECK_NE(state_, webrtc::DataChannelInterface::kOpen);
IncrementCounter(DataChannelCounters::kOpened);
state_ = webrtc::DataChannelInterface::kOpen;
+ CreateFeatureHandleForScheduler();
}
void RTCDataChannel::DispatchOpenEvent() {
@@ -536,6 +543,7 @@ void RTCDataChannel::OnStateChange(
switch (state_) {
case webrtc::DataChannelInterface::kOpen:
IncrementCounter(DataChannelCounters::kOpened);
+ CreateFeatureHandleForScheduler();
DispatchEvent(*Event::Create(event_type_names::kOpen));
break;
case webrtc::DataChannelInterface::kClosing:
@@ -544,6 +552,7 @@ void RTCDataChannel::OnStateChange(
}
break;
case webrtc::DataChannelInterface::kClosed:
+ feature_handle_for_scheduler_.reset();
if (!channel()->error().ok()) {
DispatchEvent(*MakeGarbageCollected<RTCErrorEvent>(
event_type_names::kError, channel()->error()));
@@ -647,4 +656,23 @@ bool RTCDataChannel::SendDataBuffer(webrtc::DataBuffer data_buffer) {
return true;
}
+void RTCDataChannel::CreateFeatureHandleForScheduler() {
+ DCHECK(!feature_handle_for_scheduler_);
+ LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(GetExecutionContext());
+ // Ideally we'd use To<LocalDOMWindow>, but in unittests the ExecutionContext
+ // may not be a LocalDOMWindow.
+ if (!window)
+ return;
+ // This can happen for detached frames.
+ if (!window->GetFrame())
+ return;
+ feature_handle_for_scheduler_ =
+ window->GetFrame()->GetFrameScheduler()->RegisterFeature(
+ SchedulingPolicy::Feature::kWebRTC,
+ base::FeatureList::IsEnabled(features::kOptOutWebRTCFromAllThrottling)
+ ? SchedulingPolicy{SchedulingPolicy::DisableAllThrottling()}
+ : SchedulingPolicy{
+ SchedulingPolicy::DisableAggressiveThrottling()});
+}
+
} // 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 b9265c3fc4c..5e068fe2a0d 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
@@ -35,6 +35,7 @@
#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"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/webrtc/api/peer_connection_interface.h"
@@ -166,6 +167,10 @@ class MODULES_EXPORT RTCDataChannel final
bool SendRawData(const char* data, size_t length);
bool SendDataBuffer(webrtc::DataBuffer data_buffer);
+ // Initializes |feature_handle_for_scheduler_|, which must not yet have been
+ // initialized.
+ void CreateFeatureHandleForScheduler();
+
webrtc::DataChannelInterface::DataState state_;
enum BinaryType { kBinaryTypeBlob, kBinaryTypeArrayBuffer };
@@ -178,6 +183,12 @@ class MODULES_EXPORT RTCDataChannel final
FRIEND_TEST_ALL_PREFIXES(RTCDataChannelTest, Message);
FRIEND_TEST_ALL_PREFIXES(RTCDataChannelTest, BufferedAmountLow);
+ // This handle notifies the scheduler about a connected data channel
+ // associated with a frame. The handle should be destroyed when the channel
+ // is closed.
+ FrameScheduler::SchedulingAffectingFeatureHandle
+ feature_handle_for_scheduler_;
+
unsigned buffered_amount_low_threshold_;
unsigned buffered_amount_;
bool stopped_;
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 62fea13d595..bc5de51d17e 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
@@ -13,9 +13,13 @@
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.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/events/event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -358,4 +362,39 @@ TEST_F(RTCDataChannelTest, CloseAfterContextDestroyed) {
EXPECT_EQ(String::FromUTF8("closed"), channel->readyState());
}
+TEST_F(RTCDataChannelTest, StopsThrottling) {
+ V8TestingScope scope;
+
+ auto* scheduler = scope.GetFrame().GetFrameScheduler()->GetPageScheduler();
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
+
+ // Creating an RTCDataChannel doesn't enable the opt-out.
+ scoped_refptr<MockDataChannel> webrtc_channel(
+ new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
+ std::unique_ptr<MockPeerConnectionHandler> pc(
+ new MockPeerConnectionHandler(signaling_thread()));
+ auto* channel = MakeGarbageCollected<RTCDataChannel>(
+ scope.GetExecutionContext(), webrtc_channel.get(), pc.get());
+ EXPECT_EQ("connecting", channel->readyState());
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
+
+ // Transitioning to 'open' enables the opt-out.
+ webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("open", channel->readyState());
+ EXPECT_TRUE(scheduler->OptedOutFromAggressiveThrottlingForTest());
+
+ // Transitioning to 'closing' keeps the opt-out enabled.
+ webrtc_channel->ChangeState(webrtc::DataChannelInterface::kClosing);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("closing", channel->readyState());
+ EXPECT_TRUE(scheduler->OptedOutFromAggressiveThrottlingForTest());
+
+ // Transitioning to 'closed' stops the opt-out.
+ webrtc_channel->ChangeState(webrtc::DataChannelInterface::kClosed);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ("closed", channel->readyState());
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
+}
+
} // namespace blink
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 2764b87bb6a..82a155cd0aa 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
@@ -94,7 +94,8 @@ webrtc::DtlsTransportInterface* RTCDtlsTransport::native_transport() {
}
void RTCDtlsTransport::ChangeState(webrtc::DtlsTransportInformation info) {
- DCHECK(current_state_.state() != webrtc::DtlsTransportState::kClosed);
+ DCHECK(info.state() == webrtc::DtlsTransportState::kClosed ||
+ current_state_.state() != webrtc::DtlsTransportState::kClosed);
current_state_ = info;
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.cc
index 48c9a2f0fdd..f16e6fc6265 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.cc
@@ -127,7 +127,7 @@ String RTCIceCandidate::type() const {
return platform_candidate_->Type();
}
-String RTCIceCandidate::tcpType() const {
+base::Optional<String> RTCIceCandidate::tcpType() const {
return platform_candidate_->TcpType();
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h
index c4e60a52b9c..395fc9b5c39 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h
@@ -65,7 +65,7 @@ class MODULES_EXPORT RTCIceCandidate final : public ScriptWrappable {
String protocol() const;
base::Optional<uint16_t> port() const;
String type() const;
- String tcpType() const;
+ base::Optional<String> tcpType() const;
String relatedAddress() const;
base::Optional<uint16_t> relatedPort() const;
String usernameFragment() const;
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.idl
index 56eb4812ff7..556b0b6e9c0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.idl
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.idl
@@ -24,7 +24,7 @@
*/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface RTCLegacyStatsReport {
[CallWith=ScriptState, Measure] readonly attribute object timestamp;
readonly attribute DOMString id;
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 d7415d03c12..47a1fa272e0 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
@@ -35,6 +35,7 @@
#include <string>
#include <utility>
+#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
@@ -117,6 +118,7 @@
#include "third_party/blink/renderer/platform/peerconnection/rtc_stats_request.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/webrtc/api/data_channel_interface.h"
@@ -746,13 +748,16 @@ RTCPeerConnection::RTCPeerConnection(
MediaConstraints constraints,
ExceptionState& exception_state)
: ExecutionContextLifecycleObserver(context),
+ pending_local_description_(nullptr),
+ current_local_description_(nullptr),
+ pending_remote_description_(nullptr),
+ current_remote_description_(nullptr),
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),
- negotiation_needed_(false),
peer_handler_unregistered_(true),
closed_(true),
suppress_events_(true),
@@ -815,13 +820,8 @@ RTCPeerConnection::RTCPeerConnection(
feature_handle_for_scheduler_ =
window->GetFrame()->GetFrameScheduler()->RegisterFeature(
SchedulingPolicy::Feature::kWebRTC,
- base::FeatureList::IsEnabled(features::kOptOutWebRTCFromAllThrottling)
- ? SchedulingPolicy{SchedulingPolicy::DisableAllThrottling(),
- SchedulingPolicy::
- RecordMetricsForBackForwardCache()}
- : SchedulingPolicy{
- SchedulingPolicy::DisableAggressiveThrottling(),
- SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ SchedulingPolicy{
+ SchedulingPolicy::RecordMetricsForBackForwardCache()});
}
RTCPeerConnection::~RTCPeerConnection() {
@@ -861,12 +861,16 @@ ScriptPromise RTCPeerConnection::createOffer(ScriptState* script_state,
RTCSessionDescriptionRequestPromiseImpl::Create(
RTCCreateSessionDescriptionOperation::kCreateOffer, this, resolver,
"RTCPeerConnection", "createOffer");
+
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateOffer);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateOfferPromise);
if (options->hasOfferToReceiveAudio() || options->hasOfferToReceiveVideo()) {
- ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(
context,
WebFeature::kRTCPeerConnectionCreateOfferOptionsOfferToReceive);
}
+
auto platform_transceivers = peer_handler_->CreateOffer(
request, ConvertToRTCOfferOptionsPlatform(options));
for (auto& platform_transceiver : platform_transceivers)
@@ -910,6 +914,7 @@ ScriptPromise RTCPeerConnection::CreateOffer(
ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(
context, WebFeature::kRTCPeerConnectionCreateOfferLegacyFailureCallback);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateOffer);
if (CallErrorCallbackIfSignalingStateClosed(signaling_state_, error_callback))
return ScriptPromise::CastUndefined(script_state);
@@ -978,6 +983,10 @@ ScriptPromise RTCPeerConnection::createAnswer(ScriptState* script_state,
return ScriptPromise();
}
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateAnswer);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateAnswerPromise);
+
call_setup_state_tracker_.NoteAnswererStateEvent(
AnswererState::kCreateAnswerPending, HasDocumentMedia());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -1023,6 +1032,7 @@ ScriptPromise RTCPeerConnection::CreateAnswer(
DCHECK(success_callback);
DCHECK(error_callback);
ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionCreateAnswer);
UseCounter::Count(
context, WebFeature::kRTCPeerConnectionCreateAnswerLegacyFailureCallback);
if (media_constraints.IsObject()) {
@@ -1374,6 +1384,11 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
}
NoteCallSetupStateEventPending(SetSdpOperationType::kSetLocalDescription,
*session_description_init);
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionSetLocalDescription);
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionSetLocalDescriptionPromise);
+
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
@@ -1403,6 +1418,7 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
session_description_init);
}
ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context, WebFeature::kRTCPeerConnectionSetLocalDescription);
if (success_callback && error_callback) {
UseCounter::Count(
context,
@@ -1443,28 +1459,17 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
return ScriptPromise::CastUndefined(script_state);
}
-RTCSessionDescription* RTCPeerConnection::localDescription() {
- auto* platform_session_description = peer_handler_->LocalDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::localDescription() const {
+ return pending_local_description_ ? pending_local_description_
+ : current_local_description_;
}
-RTCSessionDescription* RTCPeerConnection::currentLocalDescription() {
- auto* platform_session_description = peer_handler_->CurrentLocalDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::currentLocalDescription() const {
+ return current_local_description_;
}
-RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() {
- auto* platform_session_description = peer_handler_->PendingLocalDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() const {
+ return pending_local_description_;
}
ScriptPromise RTCPeerConnection::setRemoteDescription(
@@ -1490,6 +1495,12 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
return ScriptPromise();
}
+ ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionSetRemoteDescription);
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionSetRemoteDescriptionPromise);
+
NoteCallSetupStateEventPending(SetSdpOperationType::kSetRemoteDescription,
*session_description_init);
if (ContainsLegacyRtpDataChannel(session_description_init->sdp())) {
@@ -1526,6 +1537,8 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
session_description_init);
}
ExecutionContext* context = ExecutionContext::From(script_state);
+ UseCounter::Count(context,
+ WebFeature::kRTCPeerConnectionSetRemoteDescription);
if (success_callback && error_callback) {
UseCounter::Count(
context,
@@ -1563,30 +1576,17 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
return ScriptPromise::CastUndefined(script_state);
}
-RTCSessionDescription* RTCPeerConnection::remoteDescription() {
- auto* platform_session_description = peer_handler_->RemoteDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::remoteDescription() const {
+ return pending_remote_description_ ? pending_remote_description_
+ : current_remote_description_;
}
-RTCSessionDescription* RTCPeerConnection::currentRemoteDescription() {
- auto* platform_session_description =
- peer_handler_->CurrentRemoteDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::currentRemoteDescription() const {
+ return current_remote_description_;
}
-RTCSessionDescription* RTCPeerConnection::pendingRemoteDescription() {
- auto* platform_session_description =
- peer_handler_->PendingRemoteDescription();
- if (!platform_session_description)
- return nullptr;
-
- return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::pendingRemoteDescription() const {
+ return pending_remote_description_;
}
RTCConfiguration* RTCPeerConnection::getConfiguration(
@@ -2010,7 +2010,7 @@ String RTCPeerConnection::connectionState() const {
}
base::Optional<bool> RTCPeerConnection::canTrickleIceCandidates() const {
- if (closed_ || !peer_handler_->RemoteDescription()) {
+ if (closed_ || !remoteDescription()) {
return base::nullopt;
}
webrtc::PeerConnectionInterface* native_connection =
@@ -2836,16 +2836,6 @@ void RTCPeerConnection::OnStreamRemoveTrack(MediaStream* stream,
void RTCPeerConnection::NegotiationNeeded() {
DCHECK(!closed_);
- negotiation_needed_ = true;
- Microtask::EnqueueMicrotask(
- WTF::Bind(&RTCPeerConnection::MaybeFireNegotiationNeeded,
- WrapWeakPersistent(this)));
-}
-
-void RTCPeerConnection::MaybeFireNegotiationNeeded() {
- if (!negotiation_needed_ || closed_)
- return;
- negotiation_needed_ = false;
MaybeDispatchEvent(Event::Create(event_type_names::kNegotiationneeded));
}
@@ -2855,7 +2845,7 @@ void RTCPeerConnection::DidGenerateICECandidate(
DCHECK(GetExecutionContext()->IsContextThread());
DCHECK(platform_candidate);
RTCIceCandidate* ice_candidate = RTCIceCandidate::Create(platform_candidate);
- ScheduleDispatchEvent(RTCPeerConnectionIceEvent::Create(ice_candidate));
+ MaybeDispatchEvent(RTCPeerConnectionIceEvent::Create(ice_candidate));
}
void RTCPeerConnection::DidFailICECandidate(const String& address,
@@ -2866,15 +2856,33 @@ void RTCPeerConnection::DidFailICECandidate(const String& address,
const String& error_text) {
DCHECK(!closed_);
DCHECK(GetExecutionContext()->IsContextThread());
- ScheduleDispatchEvent(RTCPeerConnectionIceErrorEvent::Create(
+ MaybeDispatchEvent(RTCPeerConnectionIceErrorEvent::Create(
address, port, host_candidate, url, error_code, error_text));
}
-void RTCPeerConnection::DidChangeSignalingState(
- webrtc::PeerConnectionInterface::SignalingState new_state) {
+void RTCPeerConnection::DidChangeSessionDescriptions(
+ RTCSessionDescriptionPlatform* pending_local_description,
+ RTCSessionDescriptionPlatform* current_local_description,
+ RTCSessionDescriptionPlatform* pending_remote_description,
+ RTCSessionDescriptionPlatform* current_remote_description) {
DCHECK(!closed_);
DCHECK(GetExecutionContext()->IsContextThread());
- ChangeSignalingState(new_state, true);
+ pending_local_description_ =
+ pending_local_description
+ ? RTCSessionDescription::Create(pending_local_description)
+ : nullptr;
+ current_local_description_ =
+ current_local_description
+ ? RTCSessionDescription::Create(current_local_description)
+ : nullptr;
+ pending_remote_description_ =
+ pending_remote_description
+ ? RTCSessionDescription::Create(pending_remote_description)
+ : nullptr;
+ current_remote_description_ =
+ current_remote_description
+ ? RTCSessionDescription::Create(current_remote_description)
+ : nullptr;
}
void RTCPeerConnection::DidChangeIceGatheringState(
@@ -2908,98 +2916,153 @@ void RTCPeerConnection::DidChangePeerConnectionState(
ChangePeerConnectionState(new_state);
}
-void RTCPeerConnection::DidAddReceiverPlanB(
- std::unique_ptr<RTCRtpReceiverPlatform> platform_receiver) {
+void RTCPeerConnection::DidModifyReceiversPlanB(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> platform_receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>
+ platform_receivers_removed) {
DCHECK(!closed_);
DCHECK(GetExecutionContext()->IsContextThread());
DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kPlanB);
if (signaling_state_ ==
webrtc::PeerConnectionInterface::SignalingState::kClosed)
return;
- // Create track.
- auto* track = MakeGarbageCollected<MediaStreamTrack>(
- GetExecutionContext(), platform_receiver->Track());
- tracks_.insert(track->Component(), track);
- // Create or update streams.
- HeapVector<Member<MediaStream>> streams;
- for (const auto& stream_id : platform_receiver->StreamIds()) {
- MediaStream* stream = getRemoteStreamById(stream_id);
- if (!stream) {
- // The stream is new, create it containing this track.
- MediaStreamComponentVector audio_track_components;
- MediaStreamTrackVector audio_tracks;
- MediaStreamComponentVector video_track_components;
- MediaStreamTrackVector video_tracks;
- if (track->Component()->Source()->GetType() ==
- MediaStreamSource::kTypeAudio) {
- audio_track_components.push_back(track->Component());
- audio_tracks.push_back(track);
+
+ // We must complete all processing before firing events to avoid JS events
+ // influencing the algorithm or have events fire before the peer connection's
+ // state has settled.
+ HeapVector<Member<MediaStreamTrack>> mute_tracks;
+ HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>>
+ remove_list;
+ HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>> add_list;
+ HeapVector<Member<RTCRtpReceiver>> track_events;
+ MediaStreamVector previous_streams = getRemoteStreams();
+
+ // Process the addition of receivers.
+ for (auto& platform_receiver : platform_receivers_added) {
+ // Create track.
+ auto* track = MakeGarbageCollected<MediaStreamTrack>(
+ GetExecutionContext(), platform_receiver->Track());
+ tracks_.insert(track->Component(), track);
+ // Create or update streams.
+ HeapVector<Member<MediaStream>> streams;
+ for (const auto& stream_id : platform_receiver->StreamIds()) {
+ MediaStream* stream = getRemoteStreamById(stream_id);
+ if (!stream) {
+ // The stream is new, create it containing this track.
+ MediaStreamComponentVector audio_track_components;
+ MediaStreamTrackVector audio_tracks;
+ MediaStreamComponentVector video_track_components;
+ MediaStreamTrackVector video_tracks;
+ if (track->Component()->Source()->GetType() ==
+ MediaStreamSource::kTypeAudio) {
+ audio_track_components.push_back(track->Component());
+ audio_tracks.push_back(track);
+ } else {
+ DCHECK(track->Component()->Source()->GetType() ==
+ MediaStreamSource::kTypeVideo);
+ video_track_components.push_back(track->Component());
+ video_tracks.push_back(track);
+ }
+ auto* descriptor = MakeGarbageCollected<MediaStreamDescriptor>(
+ stream_id, std::move(audio_track_components),
+ std::move(video_track_components));
+ stream = MediaStream::Create(GetExecutionContext(), descriptor,
+ std::move(audio_tracks),
+ std::move(video_tracks));
} else {
- DCHECK(track->Component()->Source()->GetType() ==
- MediaStreamSource::kTypeVideo);
- video_track_components.push_back(track->Component());
- video_tracks.push_back(track);
+ // The stream already exists, the track will be added and events fired
+ // after processing the remaining receivers.
+ add_list.push_back(std::make_pair(stream, track));
}
- auto* descriptor = MakeGarbageCollected<MediaStreamDescriptor>(
- stream_id, std::move(audio_track_components),
- std::move(video_track_components));
- stream =
- MediaStream::Create(GetExecutionContext(), descriptor,
- std::move(audio_tracks), std::move(video_tracks));
- // Schedule to fire "pc.onaddstream".
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
- event_type_names::kAddstream, stream));
- } else {
- // The stream already exists, add the track to it.
- // This will cause to schedule to fire "stream.onaddtrack".
- stream->AddTrackAndFireEvents(track);
+ streams.push_back(stream);
}
- streams.push_back(stream);
+ DCHECK(FindReceiver(*platform_receiver) == rtp_receivers_.end());
+ RTCRtpReceiver* rtp_receiver = MakeGarbageCollected<RTCRtpReceiver>(
+ this, std::move(platform_receiver), track, streams,
+ force_encoded_audio_insertable_streams(),
+ force_encoded_video_insertable_streams());
+ rtp_receivers_.push_back(rtp_receiver);
+ track_events.push_back(rtp_receiver);
}
- DCHECK(FindReceiver(*platform_receiver) == rtp_receivers_.end());
- RTCRtpReceiver* rtp_receiver = MakeGarbageCollected<RTCRtpReceiver>(
- this, std::move(platform_receiver), track, streams,
- force_encoded_audio_insertable_streams(),
- force_encoded_video_insertable_streams());
- rtp_receivers_.push_back(rtp_receiver);
- ScheduleDispatchEvent(MakeGarbageCollected<RTCTrackEvent>(
- rtp_receiver, rtp_receiver->track(), streams, nullptr));
-}
-void RTCPeerConnection::DidRemoveReceiverPlanB(
- std::unique_ptr<RTCRtpReceiverPlatform> platform_receiver) {
- DCHECK(!closed_);
- DCHECK(GetExecutionContext()->IsContextThread());
- DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kPlanB);
+ // Process the removal of receivers.
+ for (auto& platform_receiver : platform_receivers_removed) {
+ auto* it = FindReceiver(*platform_receiver);
+ DCHECK(it != rtp_receivers_.end());
+ RTCRtpReceiver* rtp_receiver = *it;
+ auto streams = rtp_receiver->streams();
+ MediaStreamTrack* track = rtp_receiver->track();
+ rtp_receivers_.erase(it);
- auto* it = FindReceiver(*platform_receiver);
- DCHECK(it != rtp_receivers_.end());
- RTCRtpReceiver* rtp_receiver = *it;
- auto streams = rtp_receiver->streams();
- MediaStreamTrack* track = rtp_receiver->track();
- rtp_receivers_.erase(it);
-
- // End streams no longer in use and fire "removestream" events. This behavior
- // is no longer in the spec.
- for (const auto& stream : streams) {
- // Remove the track.
- // This will cause to schedule to fire "stream.onremovetrack".
- stream->RemoveTrackAndFireEvents(track);
-
- // Was this the last usage of the stream? Remove from remote streams.
- if (!IsRemoteStream(stream)) {
- // TODO(hbos): The stream should already have ended by being empty, no
- // need for |StreamEnded|.
- stream->StreamEnded();
- stream->UnregisterObserver(this);
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
- event_type_names::kRemovestream, stream));
+ // The track will be removed from the stream and events fired after
+ // processing the remaining receivers.
+ for (const auto& stream : streams) {
+ remove_list.push_back(std::make_pair(stream, track));
+ if (!IsRemoteStream(stream)) {
+ stream->UnregisterObserver(this);
+ }
}
+
+ // The track will be muted and events fired after processing the remaining
+ // receivers.
+ mute_tracks.push_back(track);
}
+ MediaStreamVector current_streams = getRemoteStreams();
- // Mute track and fire "onmute" if not already muted.
- track->Component()->Source()->SetReadyState(
- MediaStreamSource::kReadyStateMuted);
+ // Modify and fire "pc.onsignalingchange" synchronously.
+ if (signaling_state_ == webrtc::PeerConnectionInterface::kHaveLocalOffer &&
+ signaling_state == webrtc::PeerConnectionInterface::kHaveRemoteOffer) {
+ // Inject missing kStable in case of implicit rollback.
+ ChangeSignalingState(webrtc::PeerConnectionInterface::kStable, true);
+ }
+ ChangeSignalingState(signaling_state, true);
+
+ // Mute the tracks, this fires "track.onmute" synchronously.
+ for (auto& track : mute_tracks) {
+ track->Component()->Source()->SetReadyState(
+ MediaStreamSource::kReadyStateMuted);
+ }
+ // Remove/add tracks to streams, this fires "stream.onremovetrack" and
+ // "stream.onaddtrack" synchronously.
+ for (auto& pair : remove_list) {
+ auto& stream = pair.first;
+ auto& track = pair.second;
+ if (stream->getTracks().Contains(track)) {
+ stream->RemoveTrackAndFireEvents(
+ track,
+ MediaStreamDescriptorClient::DispatchEventTiming::kImmediately);
+ }
+ }
+ for (auto& pair : add_list) {
+ auto& stream = pair.first;
+ auto& track = pair.second;
+ if (!stream->getTracks().Contains(track)) {
+ stream->AddTrackAndFireEvents(
+ track,
+ MediaStreamDescriptorClient::DispatchEventTiming::kImmediately);
+ }
+ }
+
+ // Legacy APIs: "pc.onaddstream" and "pc.onremovestream".
+ for (const auto& current_stream : current_streams) {
+ if (!previous_streams.Contains(current_stream)) {
+ MaybeDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
+ event_type_names::kAddstream, current_stream));
+ }
+ }
+ for (const auto& previous_stream : previous_streams) {
+ if (!current_streams.Contains(previous_stream)) {
+ MaybeDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
+ event_type_names::kRemovestream, previous_stream));
+ }
+ }
+
+ // Fire "pc.ontrack" synchronously.
+ for (auto& rtp_receiver : track_events) {
+ MaybeDispatchEvent(MakeGarbageCollected<RTCTrackEvent>(
+ rtp_receiver, rtp_receiver->track(), rtp_receiver->streams(), nullptr));
+ }
}
void RTCPeerConnection::DidModifySctpTransport(
@@ -3024,16 +3087,23 @@ void RTCPeerConnection::DidModifySctpTransport(
}
void RTCPeerConnection::DidModifyTransceivers(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
Vector<std::unique_ptr<RTCRtpTransceiverPlatform>> platform_transceivers,
Vector<uintptr_t> removed_transceiver_ids,
bool is_remote_description) {
+ HeapVector<Member<MediaStreamTrack>> mute_tracks;
+ HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>>
+ remove_list;
+ HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>> add_list;
+ HeapVector<Member<RTCRtpTransceiver>> track_events;
+ MediaStreamVector previous_streams = getRemoteStreams();
for (auto id : removed_transceiver_ids) {
for (auto* it = transceivers_.begin(); it != transceivers_.end(); ++it) {
if ((*it)->platform_transceiver()->Id() == id) {
auto* track = (*it)->receiver()->track();
for (const auto& stream : (*it)->receiver()->streams()) {
if (stream->getTracks().Contains(track)) {
- stream->RemoveTrackAndFireEvents(track);
+ remove_list.push_back(std::make_pair(stream, track));
}
}
(*it)->receiver()->set_streams(MediaStreamVector());
@@ -3043,12 +3113,6 @@ void RTCPeerConnection::DidModifyTransceivers(
}
}
}
- HeapVector<Member<MediaStreamTrack>> mute_tracks;
- HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>>
- remove_list;
- HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>> add_list;
- HeapVector<Member<RTCRtpTransceiver>> track_events;
- MediaStreamVector previous_streams = getRemoteStreams();
for (auto& platform_transceiver : platform_transceivers) {
auto* it = FindTransceiver(*platform_transceiver);
bool previously_had_recv =
@@ -3082,48 +3146,63 @@ void RTCPeerConnection::DidModifyTransceivers(
mute_tracks.push_back(transceiver->receiver()->track());
}
}
+ if (sdp_semantics_ == webrtc::SdpSemantics::kUnifiedPlan) {
+ // Update the rtp_senders_ and rtp_receivers_ members to only contain
+ // senders and receivers that are in the current set of transceivers.
+ rtp_senders_.clear();
+ rtp_receivers_.clear();
+ for (auto& transceiver : transceivers_) {
+ rtp_senders_.push_back(transceiver->sender());
+ rtp_receivers_.push_back(transceiver->receiver());
+ }
+ }
+
MediaStreamVector current_streams = getRemoteStreams();
+ // Modify and fire "pc.onsignalingchange" synchronously.
+ if (signaling_state_ == webrtc::PeerConnectionInterface::kHaveLocalOffer &&
+ signaling_state == webrtc::PeerConnectionInterface::kHaveRemoteOffer) {
+ // Inject missing kStable in case of implicit rollback.
+ ChangeSignalingState(webrtc::PeerConnectionInterface::kStable, true);
+ }
+ ChangeSignalingState(signaling_state, true);
+
+ // Mute the tracks, this fires "track.onmute" synchronously.
for (auto& track : mute_tracks) {
- // Mute the track. Fires "track.onmute" synchronously.
track->Component()->Source()->SetReadyState(
MediaStreamSource::kReadyStateMuted);
}
// Remove/add tracks to streams, this fires "stream.onremovetrack" and
- // "stream.onaddtrack" asynchronously (delayed with ScheduleDispatchEvent()).
- // This means that the streams will be updated immediately, but the
- // corresponding events will fire after "pc.ontrack".
- // TODO(https://crbug.com/788558): These should probably also fire
- // synchronously (before "pc.ontrack"). The webrtc-pc spec references the
- // mediacapture-streams spec for adding and removing tracks to streams, which
- // adds/removes and fires synchronously, but it says to do this in a queued
- // task, which would lead to unexpected behavior: the streams would be empty
- // at "pc.ontrack".
+ // "stream.onaddtrack" synchronously.
for (auto& pair : remove_list) {
auto& stream = pair.first;
auto& track = pair.second;
if (stream->getTracks().Contains(track)) {
- stream->RemoveTrackAndFireEvents(track);
+ stream->RemoveTrackAndFireEvents(
+ track,
+ MediaStreamDescriptorClient::DispatchEventTiming::kImmediately);
}
}
for (auto& pair : add_list) {
auto& stream = pair.first;
auto& track = pair.second;
if (!stream->getTracks().Contains(track)) {
- stream->AddTrackAndFireEvents(track);
+ stream->AddTrackAndFireEvents(
+ track,
+ MediaStreamDescriptorClient::DispatchEventTiming::kImmediately);
}
}
// Legacy APIs: "pc.onaddstream" and "pc.onremovestream".
for (const auto& current_stream : current_streams) {
if (!previous_streams.Contains(current_stream)) {
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
+ MaybeDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
event_type_names::kAddstream, current_stream));
}
}
for (const auto& previous_stream : previous_streams) {
if (!current_streams.Contains(previous_stream)) {
- ScheduleDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
+ MaybeDispatchEvent(MakeGarbageCollected<MediaStreamEvent>(
event_type_names::kRemovestream, previous_stream));
}
}
@@ -3521,6 +3600,10 @@ void RTCPeerConnection::DispatchScheduledEvents() {
}
void RTCPeerConnection::Trace(Visitor* visitor) const {
+ visitor->Trace(pending_local_description_);
+ visitor->Trace(current_local_description_);
+ visitor->Trace(pending_remote_description_);
+ visitor->Trace(current_remote_description_);
visitor->Trace(tracks_);
visitor->Trace(rtp_senders_);
visitor->Trace(rtp_receivers_);
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 72ead12f62c..4e9fb847e5f 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
@@ -183,9 +183,9 @@ class MODULES_EXPORT RTCPeerConnection final
const RTCSessionDescriptionInit*,
V8VoidFunction*,
V8RTCPeerConnectionErrorCallback* = nullptr);
- RTCSessionDescription* localDescription();
- RTCSessionDescription* currentLocalDescription();
- RTCSessionDescription* pendingLocalDescription();
+ RTCSessionDescription* localDescription() const;
+ RTCSessionDescription* currentLocalDescription() const;
+ RTCSessionDescription* pendingLocalDescription() const;
ScriptPromise setRemoteDescription(ScriptState*,
const RTCSessionDescriptionInit*,
@@ -195,9 +195,9 @@ class MODULES_EXPORT RTCPeerConnection final
const RTCSessionDescriptionInit*,
V8VoidFunction*,
V8RTCPeerConnectionErrorCallback* = nullptr);
- RTCSessionDescription* remoteDescription();
- RTCSessionDescription* currentRemoteDescription();
- RTCSessionDescription* pendingRemoteDescription();
+ RTCSessionDescription* remoteDescription() const;
+ RTCSessionDescription* currentRemoteDescription() const;
+ RTCSessionDescription* pendingRemoteDescription() const;
String signalingState() const;
@@ -337,18 +337,25 @@ class MODULES_EXPORT RTCPeerConnection final
const String& url,
int error_code,
const String& error_text) override;
- void DidChangeSignalingState(
- webrtc::PeerConnectionInterface::SignalingState) override;
+ void DidChangeSessionDescriptions(
+ RTCSessionDescriptionPlatform* pending_local_description,
+ RTCSessionDescriptionPlatform* current_local_description,
+ RTCSessionDescriptionPlatform* pending_remote_description,
+ RTCSessionDescriptionPlatform* current_remote_description) override;
void DidChangeIceGatheringState(
webrtc::PeerConnectionInterface::IceGatheringState) override;
void DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::IceConnectionState) override;
void DidChangePeerConnectionState(
webrtc::PeerConnectionInterface::PeerConnectionState) override;
- void DidAddReceiverPlanB(std::unique_ptr<RTCRtpReceiverPlatform>) override;
- void DidRemoveReceiverPlanB(std::unique_ptr<RTCRtpReceiverPlatform>) override;
+ void DidModifyReceiversPlanB(
+ webrtc::PeerConnectionInterface::SignalingState,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> platform_receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>
+ platform_receivers_removed) override;
void DidModifySctpTransport(WebRTCSctpTransportSnapshot) override;
- void DidModifyTransceivers(Vector<std::unique_ptr<RTCRtpTransceiverPlatform>>,
+ void DidModifyTransceivers(webrtc::PeerConnectionInterface::SignalingState,
+ Vector<std::unique_ptr<RTCRtpTransceiverPlatform>>,
Vector<uintptr_t>,
bool is_remote_description) override;
void DidAddRemoteDataChannel(
@@ -453,10 +460,10 @@ class MODULES_EXPORT RTCPeerConnection final
void Dispose();
void MaybeDispatchEvent(Event*);
+ // TODO(hbos): Remove any remaining uses of ScheduleDispatchEvent.
void ScheduleDispatchEvent(Event*);
void ScheduleDispatchEvent(Event*, BoolFunction);
void DispatchScheduledEvents();
- void MaybeFireNegotiationNeeded();
MediaStreamTrack* GetTrack(MediaStreamComponent*) const;
RTCRtpSender* FindSenderForTrackAndStream(MediaStreamTrack*, MediaStream*);
HeapVector<Member<RTCRtpSender>>::iterator FindSender(
@@ -571,6 +578,10 @@ class MODULES_EXPORT RTCPeerConnection final
HeapHashSet<Member<RTCIceTransport>> ActiveIceTransports() const;
+ Member<RTCSessionDescription> pending_local_description_;
+ Member<RTCSessionDescription> current_local_description_;
+ Member<RTCSessionDescription> pending_remote_description_;
+ Member<RTCSessionDescription> current_remote_description_;
webrtc::PeerConnectionInterface::SignalingState signaling_state_;
webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state_;
webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state_;
@@ -618,7 +629,6 @@ class MODULES_EXPORT RTCPeerConnection final
FrameScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
- bool negotiation_needed_;
// When the |peer_handler_| is unregistered, the native peer connection is
// closed and disappears from the chrome://webrtc-internals page. This happens
// when page context is destroyed.
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index 404e63308cb..00446a41dc3 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -154,29 +154,6 @@ void RunSynchronousRepeatingClosure(const base::RepeatingClosure& closure,
event->Signal();
}
-// Initializes |description| if |description_callback| returns non-null,
-// otherwise does nothing.
-void GetRTCSessionDescriptionPlatformFromSessionDescriptionCallback(
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_callback,
- std::string* out_type,
- std::string* out_sdp,
- bool* success) {
- DCHECK(out_type);
- DCHECK(out_sdp);
- DCHECK(success);
-
- const webrtc::SessionDescriptionInterface* description =
- std::move(description_callback).Run();
- if (description) {
- std::string sdp;
- description->ToString(&sdp);
- *out_type = description->type();
- *out_sdp = sdp;
- *success = true;
- }
-}
-
// Converter functions from Blink types to WebRTC types.
absl::optional<bool> ConstraintToOptional(
@@ -620,9 +597,7 @@ bool IsHostnameCandidate(const RTCIceCandidatePlatform& candidate) {
const char kLocalTld[] = ".local";
if (!candidate.Address().ContainsOnlyASCIIOrEmpty())
return false;
- // TODO(crbug.com/787254): Replace with String::EndsWithIgnoringCase.
- return base::EndsWith(candidate.Address().Ascii(), kLocalTld,
- base::CompareCase::INSENSITIVE_ASCII);
+ return candidate.Address().EndsWithIgnoringASCIICase(kLocalTld);
}
} // namespace
@@ -695,87 +670,68 @@ class RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl
return;
}
- if (handler_) {
- // Copy/move some of the states to be able to use them after moving
- // |state| below.
- webrtc::PeerConnectionInterface::SignalingState signaling_state =
- states.signaling_state;
- std::unique_ptr<webrtc::SessionDescriptionInterface>
- pending_local_description(states.pending_local_description.release());
- std::unique_ptr<webrtc::SessionDescriptionInterface>
- current_local_description(states.current_local_description.release());
-
- // Process the rest of the state changes differently depending on SDP
- // semantics.
- if (sdp_semantics_ == webrtc::SdpSemantics::kPlanB) {
- ProcessStateChangesPlanB(std::move(states));
- } else {
- DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kUnifiedPlan);
- ProcessStateChangesUnifiedPlan(std::move(states));
- }
-
- // |handler_| can become null after this call.
- handler_->OnSignalingChange(signaling_state);
-
- if (tracker_ && handler_) {
- StringBuilder value;
- if (action_ ==
- PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION_IMPLICIT) {
- webrtc::SessionDescriptionInterface* created_session_description =
- nullptr;
- // Deduce which SDP was created based on signaling state.
- if (signaling_state ==
- webrtc::PeerConnectionInterface::kHaveLocalOffer &&
- pending_local_description) {
- created_session_description = pending_local_description.get();
- } else if (signaling_state ==
- webrtc::PeerConnectionInterface::kStable &&
- current_local_description) {
- created_session_description = current_local_description.get();
- }
- // Be prepared for not knowing |created_session_description|, even
- // though a successful implicit setLocalDescription() will always have
- // created a local or pending description. See
- // https://crbug.com/1019232 documenting that SLD's observer is
- // delayed in an OnMessage. It is thus conceivable that the pending or
- // local description is no longer set when examined here, even though
- // this would only happen if the application code had rare races.
- // TODO(hbos): When setLocalDescription() is updated to invoke the
- // observer synchronously, DCHECK that |created_session_description|
- // is not null here.
- if (created_session_description) {
- std::string sdp;
- created_session_description->ToString(&sdp);
- value.Append("type: ");
- value.Append(webrtc::SdpTypeToString(
- created_session_description->GetType()));
- value.Append(", sdp: ");
- value.Append(sdp.c_str());
- }
+ // Copy/move some of the states to be able to use them after moving
+ // |state| below.
+ webrtc::PeerConnectionInterface::SignalingState signaling_state =
+ states.signaling_state;
+ auto pending_local_description =
+ std::move(states.pending_local_description);
+ auto current_local_description =
+ std::move(states.current_local_description);
+ auto pending_remote_description =
+ std::move(states.pending_remote_description);
+ auto current_remote_description =
+ std::move(states.current_remote_description);
+
+ // Track result in chrome://webrtc-internals/.
+ if (tracker_ && handler_) {
+ StringBuilder value;
+ if (action_ ==
+ PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION_IMPLICIT) {
+ webrtc::SessionDescriptionInterface* created_session_description =
+ nullptr;
+ // Deduce which SDP was created based on signaling state.
+ if (signaling_state ==
+ webrtc::PeerConnectionInterface::kHaveLocalOffer &&
+ pending_local_description) {
+ created_session_description = pending_local_description.get();
+ } else if (signaling_state ==
+ webrtc::PeerConnectionInterface::kStable &&
+ current_local_description) {
+ created_session_description = current_local_description.get();
}
- tracker_->TrackSessionDescriptionCallback(
- handler_.get(), action_, "OnSuccess", value.ToString());
+ RTC_DCHECK(created_session_description);
+ std::string sdp;
+ created_session_description->ToString(&sdp);
+ value.Append("type: ");
+ value.Append(
+ webrtc::SdpTypeToString(created_session_description->GetType()));
+ value.Append(", sdp: ");
+ value.Append(sdp.c_str());
}
+ tracker_->TrackSessionDescriptionCallback(handler_.get(), action_,
+ "OnSuccess", value.ToString());
+ handler_->TrackSignalingChange(signaling_state);
}
- if (action_ == PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION) {
- // Resolve the promise in a post to ensure any events scheduled for
- // dispatching will have fired by the time the promise is resolved.
- // TODO(hbos): Don't schedule/post to fire events/resolve the promise.
- // Instead, do it all synchronously. This must happen as the last step
- // before returning so that all effects of SRD have occurred when the
- // event executes. https://crbug.com/788558
- PostCrossThreadTask(
- *main_thread_.get(), FROM_HERE,
- CrossThreadBindOnce(
- &RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl::
- ResolvePromise,
- WrapRefCounted(this)));
+
+ if (handler_) {
+ handler_->OnSessionDescriptionsUpdated(
+ std::move(pending_local_description),
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description));
+ }
+
+ // Process the rest of the state changes differently depending on SDP
+ // semantics. This fires JS events could cause |handler_| to become null.
+ if (sdp_semantics_ == webrtc::SdpSemantics::kPlanB) {
+ ProcessStateChangesPlanB(std::move(states));
} else {
- // Resolve promise immediately if we can. https://crbug.com/788558 still
- // needs to be addressed for "setLocalDescription(answer)" rejecting a
- // transceiver in Unified Plan, but this is a minor edge-case.
- ResolvePromise();
+ DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kUnifiedPlan);
+ ProcessStateChangesUnifiedPlan(std::move(states));
}
+
+ ResolvePromise();
}
private:
@@ -793,28 +749,28 @@ class RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl
// Determine which receivers have been removed before processing the
// removal as to not invalidate the iterator.
- std::vector<blink::RTCRtpReceiverImpl*> removed_receivers;
- for (auto it = handler_->rtp_receivers_.begin();
- it != handler_->rtp_receivers_.end(); ++it) {
- if (ReceiverWasRemoved(*(*it), states.transceiver_states))
- removed_receivers.push_back(it->get());
+ Vector<blink::RTCRtpReceiverImpl*> removed_receivers;
+ for (const auto& receiver : handler_->rtp_receivers_) {
+ if (ReceiverWasRemoved(*receiver, states.transceiver_states))
+ removed_receivers.push_back(receiver.get());
}
- // Process the addition of remote receivers/tracks.
+ // Process the addition and removal of remote receivers/tracks.
+ Vector<blink::RtpReceiverState> added_receiver_states;
for (auto& transceiver_state : states.transceiver_states) {
- if (handler_ && ReceiverWasAdded(transceiver_state)) {
- // |handler_| can become null after this call.
- handler_->OnAddReceiverPlanB(transceiver_state.MoveReceiverState());
+ if (ReceiverWasAdded(transceiver_state)) {
+ added_receiver_states.push_back(transceiver_state.MoveReceiverState());
}
}
- // Process the removal of remote receivers/tracks.
- for (auto* removed_receiver : removed_receivers) {
- if (handler_) {
- // |handler_| can become null after this call.
- handler_->OnRemoveReceiverPlanB(blink::RTCRtpReceiverImpl::getId(
- removed_receiver->state().webrtc_receiver().get()));
- }
+ Vector<uintptr_t> removed_receiver_ids;
+ for (const auto* removed_receiver : removed_receivers) {
+ removed_receiver_ids.push_back(blink::RTCRtpReceiverImpl::getId(
+ removed_receiver->state().webrtc_receiver().get()));
}
+ // |handler_| can become null after this call.
+ handler_->OnReceiversModifiedPlanB(states.signaling_state,
+ std::move(added_receiver_states),
+ std::move(removed_receiver_ids));
}
bool ReceiverWasAdded(const blink::RtpTransceiverState& transceiver_state) {
@@ -845,8 +801,10 @@ class RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl
DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kUnifiedPlan);
if (handler_) {
handler_->OnModifySctpTransport(std::move(states.sctp_transport_state));
+ }
+ if (handler_) {
handler_->OnModifyTransceivers(
- std::move(states.transceiver_states),
+ states.signaling_state, std::move(states.transceiver_states),
action_ == PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION);
}
}
@@ -872,9 +830,19 @@ class RTCPeerConnectionHandler::Observer
public:
Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : handler_(handler), main_thread_(task_runner) {}
+ : handler_(handler),
+ main_thread_(task_runner),
+ native_peer_connection_(nullptr) {}
~Observer() override = default;
+ void Initialize() {
+ DCHECK(main_thread_->BelongsToCurrentThread());
+ DCHECK(!native_peer_connection_);
+ DCHECK(handler_);
+ native_peer_connection_ = handler_->native_peer_connection_;
+ DCHECK(native_peer_connection_);
+ }
+
// When an RTC event log is sent back from PeerConnection, it arrives here.
void OnWebRtcEventLogWrite(const WTF::Vector<uint8_t>& output) override {
if (!main_thread_->BelongsToCurrentThread()) {
@@ -906,15 +874,15 @@ class RTCPeerConnectionHandler::Observer
base::WrapRefCounted<DataChannelInterface>(data_channel.get())));
}
- void OnRenegotiationNeeded() override {
+ void OnNegotiationNeededEvent(uint32_t event_id) override {
if (!main_thread_->BelongsToCurrentThread()) {
PostCrossThreadTask(
*main_thread_.get(), FROM_HERE,
CrossThreadBindOnce(
- &RTCPeerConnectionHandler::Observer::OnRenegotiationNeeded,
- WrapCrossThreadPersistent(this)));
+ &RTCPeerConnectionHandler::Observer::OnNegotiationNeededEvent,
+ WrapCrossThreadPersistent(this), event_id));
} else if (handler_) {
- handler_->OnRenegotiationNeeded();
+ handler_->OnNegotiationNeededEvent(event_id);
}
}
@@ -960,11 +928,28 @@ class RTCPeerConnectionHandler::Observer
}
void OnIceCandidate(const IceCandidateInterface* candidate) override {
+ DCHECK(native_peer_connection_);
std::string sdp;
if (!candidate->ToString(&sdp)) {
NOTREACHED() << "OnIceCandidate: Could not get SDP string.";
return;
}
+ // The generated candidate may have been added to the pending or current
+ // local description, take a snapshot and surface them to the main thread.
+ // Remote descriptions are also surfaced because
+ // OnSessionDescriptionsUpdated() requires all four as arguments.
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description = CopySessionDescription(
+ native_peer_connection_->pending_local_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description = CopySessionDescription(
+ native_peer_connection_->current_local_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description = CopySessionDescription(
+ native_peer_connection_->pending_remote_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description = CopySessionDescription(
+ native_peer_connection_->current_remote_description());
PostCrossThreadTask(
*main_thread_.get(), FROM_HERE,
@@ -973,7 +958,11 @@ class RTCPeerConnectionHandler::Observer
WrapCrossThreadPersistent(this), String::FromUTF8(sdp),
String::FromUTF8(candidate->sdp_mid()),
candidate->sdp_mline_index(), candidate->candidate().component(),
- candidate->candidate().address().family()));
+ candidate->candidate().address().family(),
+ std::move(pending_local_description),
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description)));
}
void OnIceCandidateError(const std::string& address,
@@ -1002,9 +991,22 @@ class RTCPeerConnectionHandler::Observer
const String& sdp_mid,
int sdp_mline_index,
int component,
- int address_family) {
+ int address_family,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description) {
DCHECK(main_thread_->BelongsToCurrentThread());
if (handler_) {
+ handler_->OnSessionDescriptionsUpdated(
+ std::move(pending_local_description),
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description));
handler_->OnIceCandidate(sdp, sdp_mid, sdp_mline_index, component,
address_family);
}
@@ -1044,6 +1046,9 @@ class RTCPeerConnectionHandler::Observer
private:
const base::WeakPtr<RTCPeerConnectionHandler> handler_;
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
+ // A copy of |handler_->native_peer_connection_| for use on the WebRTC
+ // signaling thread.
+ scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection_;
};
RTCPeerConnectionHandler::RTCPeerConnectionHandler(
@@ -1120,8 +1125,7 @@ bool RTCPeerConnectionHandler::Initialize(
configuration_.set_prerenderer_smoothing(
!blink::Platform::Current()->RTCSmoothnessAlgorithmEnabled());
- configuration_.set_experiment_cpu_load_estimator(
- base::FeatureList::IsEnabled(media::kNewEncodeCpuLoadEstimator));
+ configuration_.set_experiment_cpu_load_estimator(true);
// Configure optional SRTP configurations enabled via the command line.
configuration_.crypto_options = webrtc::CryptoOptions{};
@@ -1137,11 +1141,11 @@ bool RTCPeerConnectionHandler::Initialize(
MakeGarbageCollected<Observer>(weak_factory_.GetWeakPtr(), task_runner_);
native_peer_connection_ = dependency_factory_->CreatePeerConnection(
configuration_, frame_, peer_connection_observer_);
-
if (!native_peer_connection_.get()) {
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
}
+ peer_connection_observer_->Initialize();
if (peer_connection_tracker_) {
peer_connection_tracker_->RegisterPeerConnection(this, configuration_,
@@ -1173,6 +1177,7 @@ bool RTCPeerConnectionHandler::InitializeForTest(
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
}
+ peer_connection_observer_->Initialize();
peer_connection_tracker_ = peer_connection_tracker;
return true;
}
@@ -1497,81 +1502,6 @@ void RTCPeerConnectionHandler::SetRemoteDescription(
CrossThreadUnretained("SetRemoteDescription")));
}
-RTCSessionDescriptionPlatform* RTCPeerConnectionHandler::LocalDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::localDescription");
-
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::local_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "localDescription");
-}
-
-RTCSessionDescriptionPlatform* RTCPeerConnectionHandler::RemoteDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::remoteDescription");
-
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::remote_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "remoteDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::CurrentLocalDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::currentLocalDescription");
-
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::current_local_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "currentLocalDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::CurrentRemoteDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::currentRemoteDescription");
-
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::current_remote_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "currentRemoteDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::PendingLocalDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::pendingLocalDescription");
-
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::pending_local_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "pendingLocalDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::PendingRemoteDescription() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::pendingRemoteDescription");
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb = CrossThreadBindOnce(
- &webrtc::PeerConnectionInterface::pending_remote_description,
- native_peer_connection_);
- return GetRTCSessionDescriptionPlatformOnSignalingThread(
- std::move(description_cb), "pendingRemoteDescription");
-}
-
const webrtc::PeerConnectionInterface::RTCConfiguration&
RTCPeerConnectionHandler::GetConfiguration() const {
return configuration_;
@@ -1622,6 +1552,14 @@ void RTCPeerConnectionHandler::AddICECandidate(
auto callback_on_task_runner =
[](base::WeakPtr<RTCPeerConnectionHandler> handler_weak_ptr,
base::WeakPtr<PeerConnectionTracker> tracker_weak_ptr,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description,
RTCIceCandidatePlatform* candidate, webrtc::RTCError result,
RTCVoidRequest* request) {
// Inform tracker (chrome://webrtc-internals).
@@ -1630,6 +1568,14 @@ void RTCPeerConnectionHandler::AddICECandidate(
handler_weak_ptr.get(), candidate,
PeerConnectionTracker::SOURCE_REMOTE, result.ok());
}
+ // Update session descriptions.
+ if (handler_weak_ptr) {
+ handler_weak_ptr->OnSessionDescriptionsUpdated(
+ std::move(pending_local_description),
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description));
+ }
// Resolve promise.
if (result.ok())
request->RequestSucceeded();
@@ -1639,12 +1585,26 @@ void RTCPeerConnectionHandler::AddICECandidate(
native_peer_connection_->AddIceCandidate(
std::move(native_candidate),
- [task_runner = task_runner_,
+ [pc = native_peer_connection_, task_runner = task_runner_,
handler_weak_ptr = weak_factory_.GetWeakPtr(),
tracker_weak_ptr = peer_connection_tracker_, candidate,
persistent_request = WrapCrossThreadPersistent(request),
callback_on_task_runner =
std::move(callback_on_task_runner)](webrtc::RTCError result) {
+ // Grab a snapshot of all the session descriptions. AddIceCandidate may
+ // have modified the remote description.
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description =
+ CopySessionDescription(pc->pending_local_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description =
+ CopySessionDescription(pc->current_local_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description =
+ CopySessionDescription(pc->pending_remote_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description =
+ CopySessionDescription(pc->current_remote_description());
// This callback is invoked on the webrtc signaling thread (this is true
// in production, not in rtc_peer_connection_handler_test.cc which uses
// a fake |native_peer_connection_|). Jump back to the renderer thread.
@@ -1652,8 +1612,12 @@ void RTCPeerConnectionHandler::AddICECandidate(
*task_runner, FROM_HERE,
WTF::CrossThreadBindOnce(
std::move(callback_on_task_runner), handler_weak_ptr,
- tracker_weak_ptr, WrapCrossThreadPersistent(candidate),
- std::move(result), std::move(persistent_request)));
+ tracker_weak_ptr, std::move(pending_local_description),
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description),
+ WrapCrossThreadPersistent(candidate), std::move(result),
+ std::move(persistent_request)));
});
}
@@ -2226,11 +2190,39 @@ void RTCPeerConnectionHandler::RunSynchronousRepeatingClosureOnSignalingThread(
}
}
-void RTCPeerConnectionHandler::OnSignalingChange(
+void RTCPeerConnectionHandler::OnSessionDescriptionsUpdated(
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description) {
+ if (!client_ || is_closed_)
+ return;
+ client_->DidChangeSessionDescriptions(
+ pending_local_description
+ ? CreateWebKitSessionDescription(pending_local_description.get())
+ : nullptr,
+ current_local_description
+ ? CreateWebKitSessionDescription(current_local_description.get())
+ : nullptr,
+ pending_remote_description
+ ? CreateWebKitSessionDescription(pending_remote_description.get())
+ : nullptr,
+ current_remote_description
+ ? CreateWebKitSessionDescription(current_remote_description.get())
+ : nullptr);
+}
+
+// Note: This function is purely for chrome://webrtc-internals/ tracking
+// purposes. The JavaScript visible event and attribute is processed together
+// with transceiver or receiver changes.
+void RTCPeerConnectionHandler::TrackSignalingChange(
webrtc::PeerConnectionInterface::SignalingState new_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnSignalingChange");
-
+ TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::TrackSignalingChange");
if (previous_signaling_state_ ==
webrtc::PeerConnectionInterface::kHaveLocalOffer &&
new_state == webrtc::PeerConnectionInterface::kHaveRemoteOffer) {
@@ -2238,18 +2230,10 @@ void RTCPeerConnectionHandler::OnSignalingChange(
auto stable_state = webrtc::PeerConnectionInterface::kStable;
if (peer_connection_tracker_)
peer_connection_tracker_->TrackSignalingStateChange(this, stable_state);
- if (!is_closed_)
- client_->DidChangeSignalingState(stable_state);
- // The callback may have closed the PC. If so, do not continue.
- if (is_closed_ || !client_) {
- return;
- }
}
previous_signaling_state_ = new_state;
if (peer_connection_tracker_)
peer_connection_tracker_->TrackSignalingStateChange(this, new_state);
- if (!is_closed_)
- client_->DidChangeSignalingState(new_state);
}
// Called any time the IceConnectionState changes
@@ -2335,86 +2319,105 @@ void RTCPeerConnectionHandler::OnIceGatheringChange(
client_->DidChangeIceGatheringState(new_state);
}
-void RTCPeerConnectionHandler::OnRenegotiationNeeded() {
+void RTCPeerConnectionHandler::OnNegotiationNeededEvent(uint32_t event_id) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRenegotiationNeeded");
+ TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnNegotiationNeededEvent");
+ if (is_closed_)
+ return;
+ if (!native_peer_connection_->ShouldFireNegotiationNeededEvent(event_id)) {
+ return;
+ }
if (peer_connection_tracker_)
peer_connection_tracker_->TrackOnRenegotiationNeeded(this);
- if (!is_closed_)
- client_->NegotiationNeeded();
+ client_->NegotiationNeeded();
}
-void RTCPeerConnectionHandler::OnAddReceiverPlanB(
- blink::RtpReceiverState receiver_state) {
+void RTCPeerConnectionHandler::OnReceiversModifiedPlanB(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<blink::RtpReceiverState> added_receiver_states,
+ Vector<uintptr_t> removed_receiver_ids) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
- DCHECK(receiver_state.is_initialized());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddReceiverPlanB");
- auto* track = receiver_state.track_ref()->track();
- // Update metrics.
- track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
- MediaStreamTrackMetricsKind(track),
- track->Id().Utf8());
- for (const auto& stream_id : receiver_state.stream_ids()) {
- // New remote stream?
- if (!IsRemoteStream(rtp_receivers_, stream_id)) {
- blink::PerSessionWebRTCAPIMetrics::GetInstance()
- ->IncrementStreamCounter();
+ TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnReceiversModifiedPlanB");
+
+ // Process the addition of receivers.
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> platform_receivers_added;
+ for (blink::RtpReceiverState& receiver_state : added_receiver_states) {
+ DCHECK(receiver_state.is_initialized());
+ auto* track = receiver_state.track_ref()->track();
+ // Update metrics.
+ track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+ MediaStreamTrackMetricsKind(track),
+ track->Id().Utf8());
+ for (const auto& stream_id : receiver_state.stream_ids()) {
+ // New remote stream?
+ if (!IsRemoteStream(rtp_receivers_, stream_id)) {
+ blink::PerSessionWebRTCAPIMetrics::GetInstance()
+ ->IncrementStreamCounter();
+ }
}
+ uintptr_t receiver_id = blink::RTCRtpReceiverImpl::getId(
+ receiver_state.webrtc_receiver().get());
+ DCHECK(FindReceiver(receiver_id) == rtp_receivers_.end());
+ auto rtp_receiver = std::make_unique<blink::RTCRtpReceiverImpl>(
+ native_peer_connection_, std::move(receiver_state),
+ force_encoded_audio_insertable_streams_,
+ force_encoded_video_insertable_streams_);
+ rtp_receivers_.push_back(
+ std::make_unique<blink::RTCRtpReceiverImpl>(*rtp_receiver));
+ if (peer_connection_tracker_) {
+ auto receiver_only_transceiver =
+ std::make_unique<blink::RTCRtpReceiverOnlyTransceiver>(
+ std::make_unique<blink::RTCRtpReceiverImpl>(*rtp_receiver));
+ size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
+ peer_connection_tracker_->TrackAddTransceiver(
+ this,
+ PeerConnectionTracker::TransceiverUpdatedReason::
+ kSetRemoteDescription,
+ *receiver_only_transceiver.get(), receiver_index);
+ }
+
+ platform_receivers_added.push_back(rtp_receiver->ShallowCopy());
}
- uintptr_t receiver_id =
- blink::RTCRtpReceiverImpl::getId(receiver_state.webrtc_receiver().get());
- DCHECK(FindReceiver(receiver_id) == rtp_receivers_.end());
- auto rtp_receiver = std::make_unique<blink::RTCRtpReceiverImpl>(
- native_peer_connection_, std::move(receiver_state),
- force_encoded_audio_insertable_streams_,
- force_encoded_video_insertable_streams_);
- rtp_receivers_.push_back(
- std::make_unique<blink::RTCRtpReceiverImpl>(*rtp_receiver));
- if (peer_connection_tracker_) {
- auto receiver_only_transceiver =
- std::make_unique<blink::RTCRtpReceiverOnlyTransceiver>(
- std::make_unique<blink::RTCRtpReceiverImpl>(*rtp_receiver));
- size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
- peer_connection_tracker_->TrackAddTransceiver(
- this,
- PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
- *receiver_only_transceiver.get(), receiver_index);
- }
- if (!is_closed_)
- client_->DidAddReceiverPlanB(rtp_receiver->ShallowCopy());
-}
-void RTCPeerConnectionHandler::OnRemoveReceiverPlanB(uintptr_t receiver_id) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRemoveReceiverPlanB");
-
- auto it = FindReceiver(receiver_id);
- DCHECK(it != rtp_receivers_.end());
- auto receiver = std::make_unique<blink::RTCRtpReceiverImpl>(*(*it));
- // Update metrics.
- track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
- MediaStreamTrackMetricsKind(receiver->Track()),
- receiver->Track()->Id().Utf8());
- if (peer_connection_tracker_) {
- auto receiver_only_transceiver =
- std::make_unique<blink::RTCRtpReceiverOnlyTransceiver>(
- std::make_unique<blink::RTCRtpReceiverImpl>(*receiver));
- size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
- peer_connection_tracker_->TrackRemoveTransceiver(
- this,
- PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
- *receiver_only_transceiver.get(), receiver_index);
- }
- rtp_receivers_.erase(it);
- for (const auto& stream_id : receiver->state().stream_ids()) {
- // This was the last occurence of the stream?
- if (!IsRemoteStream(rtp_receivers_, stream_id)) {
- blink::PerSessionWebRTCAPIMetrics::GetInstance()
- ->IncrementStreamCounter();
+ // Process the removal of receivers.
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>> platform_receivers_removed;
+ for (uintptr_t receiver_id : removed_receiver_ids) {
+ auto it = FindReceiver(receiver_id);
+ DCHECK(it != rtp_receivers_.end());
+ auto receiver = std::make_unique<blink::RTCRtpReceiverImpl>(*(*it));
+ // Update metrics.
+ track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
+ MediaStreamTrackMetricsKind(receiver->Track()),
+ receiver->Track()->Id().Utf8());
+ if (peer_connection_tracker_) {
+ auto receiver_only_transceiver =
+ std::make_unique<blink::RTCRtpReceiverOnlyTransceiver>(
+ std::make_unique<blink::RTCRtpReceiverImpl>(*receiver));
+ size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
+ peer_connection_tracker_->TrackRemoveTransceiver(
+ this,
+ PeerConnectionTracker::TransceiverUpdatedReason::
+ kSetRemoteDescription,
+ *receiver_only_transceiver.get(), receiver_index);
}
+ rtp_receivers_.erase(it);
+ for (const auto& stream_id : receiver->state().stream_ids()) {
+ // This was the last occurence of the stream?
+ if (!IsRemoteStream(rtp_receivers_, stream_id)) {
+ blink::PerSessionWebRTCAPIMetrics::GetInstance()
+ ->IncrementStreamCounter();
+ }
+ }
+
+ platform_receivers_removed.push_back(std::move(receiver));
+ }
+
+ // Surface changes to RTCPeerConnection.
+ if (!is_closed_) {
+ client_->DidModifyReceiversPlanB(signaling_state,
+ std::move(platform_receivers_added),
+ std::move(platform_receivers_removed));
}
- if (!is_closed_)
- client_->DidRemoveReceiverPlanB(std::move(receiver));
}
void RTCPeerConnectionHandler::OnModifySctpTransport(
@@ -2424,6 +2427,7 @@ void RTCPeerConnectionHandler::OnModifySctpTransport(
}
void RTCPeerConnectionHandler::OnModifyTransceivers(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
std::vector<blink::RtpTransceiverState> transceiver_states,
bool is_remote_description) {
DCHECK_EQ(configuration_.sdp_semantics, webrtc::SdpSemantics::kUnifiedPlan);
@@ -2486,7 +2490,8 @@ void RTCPeerConnectionHandler::OnModifyTransceivers(
}
previous_transceiver_ids_ = ids;
if (!is_closed_) {
- client_->DidModifyTransceivers(std::move(platform_transceivers),
+ client_->DidModifyTransceivers(signaling_state,
+ std::move(platform_transceivers),
removed_transceivers, is_remote_description);
}
}
@@ -2709,35 +2714,6 @@ RTCPeerConnectionHandler::signaling_thread() const {
return dependency_factory_->GetWebRtcSignalingTaskRunner();
}
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::GetRTCSessionDescriptionPlatformOnSignalingThread(
- CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
- description_cb,
- const char* log_text) {
- // Since the webrtc::PeerConnectionInterface::*_description() functions
- // return a pointer to a non-reference-counted object that lives on the
- // signaling thread, we cannot fetch a pointer to it and use it directly
- // here.
- // Instead, we access the object completely on the signaling thread.
- // Initializing |description| on the signaling thread is safe because we
- // own it and wait for it to be initialized here.
-
- std::string type, sdp;
- bool success = false;
- RunSynchronousOnceClosureOnSignalingThread(
- CrossThreadBindOnce(
- &GetRTCSessionDescriptionPlatformFromSessionDescriptionCallback,
- std::move(description_cb), CrossThreadUnretained(&type),
- CrossThreadUnretained(&sdp), CrossThreadUnretained(&success)),
- log_text);
-
- if (!success)
- return nullptr;
-
- return MakeGarbageCollected<RTCSessionDescriptionPlatform>(
- String::FromUTF8(type), String::FromUTF8(sdp));
-}
-
void RTCPeerConnectionHandler::ReportICEState(
webrtc::PeerConnectionInterface::IceConnectionState new_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
index f2fe772900f..13c92ab732f 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
@@ -154,13 +154,6 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
virtual void SetRemoteDescription(blink::RTCVoidRequest* request,
RTCSessionDescriptionPlatform* description);
- virtual RTCSessionDescriptionPlatform* LocalDescription();
- virtual RTCSessionDescriptionPlatform* RemoteDescription();
- virtual RTCSessionDescriptionPlatform* CurrentLocalDescription();
- virtual RTCSessionDescriptionPlatform* CurrentRemoteDescription();
- virtual RTCSessionDescriptionPlatform* PendingLocalDescription();
- virtual RTCSessionDescriptionPlatform* PendingRemoteDescription();
-
virtual const webrtc::PeerConnectionInterface::RTCConfiguration&
GetConfiguration() const;
virtual webrtc::RTCErrorType SetConfiguration(
@@ -259,7 +252,16 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
class SetLocalDescriptionRequest;
friend class SetLocalDescriptionRequest;
- void OnSignalingChange(
+ void OnSessionDescriptionsUpdated(
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description);
+ void TrackSignalingChange(
webrtc::PeerConnectionInterface::SignalingState new_state);
void OnIceConnectionChange(
webrtc::PeerConnectionInterface::IceConnectionState new_state);
@@ -269,11 +271,14 @@ class MODULES_EXPORT RTCPeerConnectionHandler {
webrtc::PeerConnectionInterface::PeerConnectionState new_state);
void OnIceGatheringChange(
webrtc::PeerConnectionInterface::IceGatheringState new_state);
- void OnRenegotiationNeeded();
- void OnAddReceiverPlanB(blink::RtpReceiverState receiver_state);
- void OnRemoveReceiverPlanB(uintptr_t receiver_id);
+ void OnNegotiationNeededEvent(uint32_t event_id);
+ void OnReceiversModifiedPlanB(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<blink::RtpReceiverState> receiver_state,
+ Vector<uintptr_t> receiver_id);
void OnModifySctpTransport(blink::WebRTCSctpTransportSnapshot state);
void OnModifyTransceivers(
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
std::vector<blink::RtpTransceiverState> transceiver_states,
bool is_remote_description);
void OnDataChannel(scoped_refptr<webrtc::DataChannelInterface> channel);
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
index 62b3751305b..eae548e3a6e 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
@@ -610,10 +610,6 @@ TEST_F(RTCPeerConnectionHandlerTest, NoCallbacksToClientAfterStop) {
mock_dependency_factory_->CreateIceCandidate("sdpMid", 1, kDummySdp));
pc_handler_->observer()->OnIceCandidate(native_candidate.get());
- EXPECT_CALL(*mock_client_.get(), DidChangeSignalingState(_)).Times(0);
- pc_handler_->observer()->OnSignalingChange(
- webrtc::PeerConnectionInterface::kHaveRemoteOffer);
-
EXPECT_CALL(*mock_client_.get(), DidChangeIceGatheringState(_)).Times(0);
pc_handler_->observer()->OnIceGatheringChange(
webrtc::PeerConnectionInterface::kIceGatheringNew);
@@ -622,12 +618,14 @@ TEST_F(RTCPeerConnectionHandlerTest, NoCallbacksToClientAfterStop) {
pc_handler_->observer()->OnIceConnectionChange(
webrtc::PeerConnectionInterface::kIceConnectionDisconnected);
- EXPECT_CALL(*mock_client_.get(), DidAddReceiverPlanBForMock(_)).Times(0);
+ EXPECT_CALL(*mock_client_.get(), DidModifyReceiversPlanBForMock(_, _, _))
+ .Times(0);
rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
AddRemoteMockMediaStream("remote_stream", "video", "audio"));
InvokeOnAddStream(remote_stream);
- EXPECT_CALL(*mock_client_.get(), DidRemoveReceiverPlanBForMock(_)).Times(0);
+ EXPECT_CALL(*mock_client_.get(), DidModifyReceiversPlanBForMock(_, _, _))
+ .Times(0);
InvokeOnRemoveStream(remote_stream);
EXPECT_CALL(*mock_client_.get(), DidAddRemoteDataChannel(_)).Times(0);
@@ -676,8 +674,6 @@ TEST_F(RTCPeerConnectionHandlerTest, setLocalDescription) {
pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
RunMessageLoopsUntilIdle();
- EXPECT_EQ(description->GetType(), pc_handler_->LocalDescription()->GetType());
- EXPECT_EQ(description->Sdp(), pc_handler_->LocalDescription()->Sdp());
std::string sdp_string;
ASSERT_TRUE(mock_peer_connection_->local_description());
@@ -711,8 +707,6 @@ TEST_F(RTCPeerConnectionHandlerTest, setLocalDescriptionParseError) {
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
RunMessageLoopsUntilIdle();
- // A description that failed to be applied shouldn't be stored.
- EXPECT_TRUE(!pc_handler_->LocalDescription());
}
TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
@@ -730,9 +724,6 @@ TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
RunMessageLoopsUntilIdle();
- EXPECT_EQ(description->GetType(),
- pc_handler_->RemoteDescription()->GetType());
- EXPECT_EQ(description->Sdp(), pc_handler_->RemoteDescription()->Sdp());
std::string sdp_string;
ASSERT_TRUE(mock_peer_connection_->remote_description());
@@ -766,8 +757,6 @@ TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescriptionParseError) {
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
RunMessageLoopsUntilIdle();
- // A description that failed to be applied shouldn't be stored.
- EXPECT_TRUE(!pc_handler_->RemoteDescription());
}
TEST_F(RTCPeerConnectionHandlerTest, setConfiguration) {
@@ -1202,13 +1191,25 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) {
TEST_F(RTCPeerConnectionHandlerTest, DISABLED_OnAddAndOnRemoveStream) {
rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
AddRemoteMockMediaStream("remote_stream", "video", "audio"));
- // Grab the added receivers when it's been successfully added to the PC.
+ // Grab receivers when they're added to/removed from the PC.
std::vector<std::unique_ptr<RTCRtpReceiverPlatform>> receivers_added;
- EXPECT_CALL(*mock_client_.get(), DidAddReceiverPlanBForMock(_))
- .WillRepeatedly(
- Invoke([&receivers_added](
- std::unique_ptr<RTCRtpReceiverPlatform>* receiver) {
- receivers_added.push_back(std::move(*receiver));
+ std::vector<std::unique_ptr<RTCRtpReceiverPlatform>> receivers_removed;
+ EXPECT_CALL(*mock_client_.get(), DidModifyReceiversPlanBForMock(_, _, _))
+ .WillRepeatedly(Invoke(
+ [&receivers_added, &receivers_removed](
+ webrtc::PeerConnectionInterface::SignalingState signaling_state,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>*
+ platform_receivers_added,
+ Vector<std::unique_ptr<RTCRtpReceiverPlatform>>*
+ platform_receivers_removed) {
+ if (!platform_receivers_added->IsEmpty()) {
+ receivers_added.push_back(
+ std::move((*platform_receivers_added)[0]));
+ }
+ if (!platform_receivers_removed->IsEmpty()) {
+ receivers_removed.push_back(
+ std::move((*platform_receivers_removed)[0]));
+ }
}));
EXPECT_CALL(
*mock_tracker_.get(),
@@ -1216,20 +1217,12 @@ TEST_F(RTCPeerConnectionHandlerTest, DISABLED_OnAddAndOnRemoveStream) {
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack, _, _))
.Times(2);
- // Grab the removed receivers when it's been successfully added to the PC.
- std::vector<std::unique_ptr<RTCRtpReceiverPlatform>> receivers_removed;
EXPECT_CALL(
*mock_tracker_.get(),
TrackRemoveTransceiver(
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack, _, _))
.Times(2);
- EXPECT_CALL(*mock_client_.get(), DidRemoveReceiverPlanBForMock(_))
- .WillRepeatedly(
- Invoke([&receivers_removed](
- std::unique_ptr<RTCRtpReceiverPlatform>* receiver) {
- receivers_removed.push_back(std::move(*receiver));
- }));
InvokeOnAddStream(remote_stream);
RunMessageLoopsUntilIdle();
@@ -1264,7 +1257,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnRenegotiationNeeded) {
EXPECT_CALL(*mock_tracker_.get(),
TrackOnRenegotiationNeeded(pc_handler_.get()));
EXPECT_CALL(*mock_client_.get(), NegotiationNeeded());
- pc_handler_->observer()->OnRenegotiationNeeded();
+ pc_handler_->observer()->OnNegotiationNeededEvent(42);
}
TEST_F(RTCPeerConnectionHandlerTest, CreateDataChannel) {
@@ -1293,11 +1286,24 @@ TEST_F(RTCPeerConnectionHandlerTest, CheckInsertableStreamsConfig) {
}
}
-TEST_F(RTCPeerConnectionHandlerTest, ThermalResourceIsDisabledByDefault) {
+TEST_F(RTCPeerConnectionHandlerTest, ThermalResourceIsEnabledByDefault) {
+ EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
+ pc_handler_->OnThermalStateChange(
+ base::PowerObserver::DeviceThermalState::kCritical);
+ // A ThermalResource is created in response to the thermal signal.
+ EXPECT_FALSE(mock_peer_connection_->adaptation_resources().IsEmpty());
+}
+
+TEST_F(RTCPeerConnectionHandlerTest,
+ ThermalStateChangeDoesNothingIfThermalResourceIsDisabled) {
+ // Overwrite base::Feature kWebRtcThermalResource's default to DISABLED.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(kWebRtcThermalResource);
+
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
pc_handler_->OnThermalStateChange(
base::PowerObserver::DeviceThermalState::kCritical);
- // A ThermalResource is not created despite the thermal signal.
+ // A ThermalResource is created in response to the thermal signal.
EXPECT_TRUE(mock_peer_connection_->adaptation_resources().IsEmpty());
}
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 a229bbb157e..1e6208438d5 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
@@ -1150,71 +1150,31 @@ TEST(DeduceSdpUsageCategory, ComplexSdpIsSafeIfMatchingExplicitSdpSemantics) {
true, webrtc::SdpSemantics::kUnifiedPlan));
}
-// This test was originally extracted out of [1], so that core/ does not need
-// to depend on mobules/.
-//
-// [1] core/scheduler_integration_tests/scheduler_affecting_features_test.cc
-//
-// TODO(crbug.com/787254): Consider factorying
-// SchedulingAffectingWebRTCFeaturesTest out to avoid the code duplication.
-class SchedulingAffectingWebRTCFeaturesTest : public SimTest {
- public:
- PageScheduler* PageScheduler() {
- return MainFrameScheduler()->GetPageScheduler();
- }
-
- FrameScheduler* MainFrameScheduler() { return MainFrame().Scheduler(); }
-
- // Some features (e.g. document.load) are expected to appear in almost
- // any output. Filter them out to make most of the tests simpler.
- Vector<SchedulingPolicy::Feature> GetNonTrivialMainFrameFeatures() {
- Vector<SchedulingPolicy::Feature> result;
- for (SchedulingPolicy::Feature feature :
- MainFrameScheduler()
- ->GetActiveFeaturesTrackedForBackForwardCacheMetrics()) {
- if (feature != SchedulingPolicy::Feature::kWebRTC)
- continue;
- result.push_back(feature);
- }
- return result;
- }
-
- std::unique_ptr<RTCPeerConnectionHandler> CreateRTCPeerConnectionHandler() {
- return std::make_unique<MockRTCPeerConnectionHandlerPlatform>();
- }
-};
-
-TEST_F(SchedulingAffectingWebRTCFeaturesTest, WebRTCStopsThrottling) {
- ScopedTestingPlatformSupport<TestingPlatformSupport> platform;
-
- RTCPeerConnection::SetRtcPeerConnectionHandlerFactoryForTesting(
- base::BindRepeating(&SchedulingAffectingWebRTCFeaturesTest::
- CreateRTCPeerConnectionHandler,
- base::Unretained(this)));
-
- SimRequest main_resource("https://example.com/", "text/html");
-
- LoadURL("https://example.com/");
-
- EXPECT_FALSE(PageScheduler()->OptedOutFromAggressiveThrottlingForTest());
- EXPECT_THAT(GetNonTrivialMainFrameFeatures(),
- testing::UnorderedElementsAre());
+TEST_F(RTCPeerConnectionTest, MediaStreamTrackStopsThrottling) {
+ V8TestingScope scope;
- main_resource.Complete(
- "<script>"
- " var data_channel = new RTCPeerConnection();"
- "</script>");
+ auto* scheduler = scope.GetFrame().GetFrameScheduler()->GetPageScheduler();
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
- EXPECT_TRUE(PageScheduler()->OptedOutFromAggressiveThrottlingForTest());
- EXPECT_THAT(
- GetNonTrivialMainFrameFeatures(),
- testing::UnorderedElementsAre(SchedulingPolicy::Feature::kWebRTC));
+ // Creating the RTCPeerConnection doesn't disable throttling.
+ RTCPeerConnection* pc = CreatePC(scope);
+ EXPECT_EQ("", GetExceptionMessage(scope));
+ ASSERT_TRUE(pc);
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
- MainFrame().ExecuteScript(WebString("data_channel.close();"));
+ // But creating a media stream track does.
+ MediaStreamTrack* track =
+ CreateTrack(scope, MediaStreamSource::kTypeAudio, "audioTrack");
+ HeapVector<Member<MediaStreamTrack>> tracks;
+ tracks.push_back(track);
+ MediaStream* stream =
+ MediaStream::Create(scope.GetExecutionContext(), tracks);
+ ASSERT_TRUE(stream);
+ EXPECT_TRUE(scheduler->OptedOutFromAggressiveThrottlingForTest());
- EXPECT_FALSE(PageScheduler()->OptedOutFromAggressiveThrottlingForTest());
- EXPECT_THAT(GetNonTrivialMainFrameFeatures(),
- testing::UnorderedElementsAre());
+ // Stopping the track disables the opt-out.
+ track->stopTrack(scope.GetExecutionContext());
+ EXPECT_FALSE(scheduler->OptedOutFromAggressiveThrottlingForTest());
}
} // namespace blink
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 0a9cf5b127d..fc46e57ab85 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
@@ -212,6 +212,7 @@ void RTCRtpTransceiver::stop(ExceptionState& exception_state) {
return;
}
stopped_ = true;
+ UpdateMembers();
}
void RTCRtpTransceiver::setCodecPreferences(
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc
index 900be89abcb..f88d1933307 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc
@@ -256,7 +256,12 @@ class RTCRtpTransceiverImpl::RTCRtpTransceiverInternal
return error;
}
- webrtc::RTCError Stop() { return webrtc_transceiver_->StopStandard(); }
+ webrtc::RTCError Stop() {
+ auto error = webrtc_transceiver_->StopStandard();
+ // After stop(), direction always returns 'stopped'.
+ state_.set_direction(webrtc::RtpTransceiverDirection::kStopped);
+ return error;
+ }
webrtc::RTCError setCodecPreferences(
std::vector<webrtc::RtpCodecCapability> codec_preferences) {
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 92bc2034602..913e15454f1 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
@@ -24,7 +24,7 @@
*/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface RTCStatsResponse {
sequence<RTCLegacyStatsReport> result();
RTCLegacyStatsReport namedItem(optional DOMString name = "undefined");
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc
index b87939fcc65..55e2b82c2a0 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/thermal_resource.cc
@@ -15,7 +15,7 @@ const int kReportIntervalSeconds = 10;
} // namespace
const base::Feature kWebRtcThermalResource{"WebRtcThermalResource",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// static
scoped_refptr<ThermalResource> ThermalResource::Create(
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
index d917c906b7f..986608080f2 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
@@ -112,7 +112,13 @@ class AudioDeviceFactoryTestingPlatformSupport : public blink::Platform {
} // namespace
-class WebRtcAudioRendererTest : public testing::Test {
+// Flaky on TSAN. See https://crbug.com/1127211
+#if defined(THREAD_SANITIZER)
+#define MAYBE_WebRtcAudioRendererTest DISABLED_WebRtcAudioRendererTest
+#else
+#define MAYBE_WebRtcAudioRendererTest WebRtcAudioRendererTest
+#endif
+class MAYBE_WebRtcAudioRendererTest : public testing::Test {
public:
MOCK_METHOD1(MockSwitchDeviceCallback, void(media::OutputDeviceStatus));
void SwitchDeviceCallback(base::RunLoop* loop,
@@ -122,7 +128,7 @@ class WebRtcAudioRendererTest : public testing::Test {
}
protected:
- WebRtcAudioRendererTest()
+ MAYBE_WebRtcAudioRendererTest()
: source_(new MockAudioRendererSource())
// Tests crash on Android if these are defined. https://crbug.com/1119689
#if !defined(OS_ANDROID)
@@ -216,7 +222,7 @@ class WebRtcAudioRendererTest : public testing::Test {
};
// Verify that the renderer will be stopped if the only proxy is stopped.
-TEST_F(WebRtcAudioRendererTest, StopRenderer) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, StopRenderer) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
@@ -229,7 +235,7 @@ TEST_F(WebRtcAudioRendererTest, StopRenderer) {
// Verify that the renderer will not be stopped unless the last proxy is
// stopped.
-TEST_F(WebRtcAudioRendererTest, MultipleRenderers) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, MultipleRenderers) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
@@ -263,7 +269,7 @@ TEST_F(WebRtcAudioRendererTest, MultipleRenderers) {
// Verify that the sink of the renderer is using the expected sample rate and
// buffer size.
-TEST_F(WebRtcAudioRendererTest, VerifySinkParameters) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, VerifySinkParameters) {
SetupRenderer(kDefaultOutputDeviceId);
renderer_proxy_->Start();
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
@@ -285,7 +291,7 @@ TEST_F(WebRtcAudioRendererTest, VerifySinkParameters) {
renderer_proxy_->Stop();
}
-TEST_F(WebRtcAudioRendererTest, NonDefaultDevice) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, NonDefaultDevice) {
SetupRenderer(kDefaultOutputDeviceId);
EXPECT_EQ(kDefaultOutputDeviceId,
mock_sink()->GetOutputDeviceInfo().device_id());
@@ -305,7 +311,7 @@ TEST_F(WebRtcAudioRendererTest, NonDefaultDevice) {
renderer_proxy_->Stop();
}
-TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDevice) {
SetupRenderer(kDefaultOutputDeviceId);
EXPECT_EQ(kDefaultOutputDeviceId,
mock_sink()->GetOutputDeviceInfo().device_id());
@@ -325,7 +331,7 @@ TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) {
base::RunLoop loop;
renderer_proxy_->SwitchOutputDevice(
kOtherOutputDeviceId,
- base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback,
+ base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback,
base::Unretained(this), &loop));
loop.Run();
EXPECT_EQ(kOtherOutputDeviceId,
@@ -340,7 +346,7 @@ TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) {
renderer_proxy_->Stop();
}
-TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) {
SetupRenderer(kDefaultOutputDeviceId);
EXPECT_EQ(kDefaultOutputDeviceId,
mock_sink()->GetOutputDeviceInfo().device_id());
@@ -357,7 +363,7 @@ TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) {
base::RunLoop loop;
renderer_proxy_->SwitchOutputDevice(
kInvalidOutputDeviceId,
- base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback,
+ base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback,
base::Unretained(this), &loop));
loop.Run();
EXPECT_EQ(kDefaultOutputDeviceId,
@@ -372,7 +378,7 @@ TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) {
renderer_proxy_->Stop();
}
-TEST_F(WebRtcAudioRendererTest, InitializeWithInvalidDevice) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, InitializeWithInvalidDevice) {
renderer_ = new blink::WebRtcAudioRenderer(
scheduler::GetSingleThreadTaskRunnerForTesting(), stream_descriptor_,
nullptr /*blink::WebLocalFrame*/, base::UnguessableToken::Create(),
@@ -397,7 +403,7 @@ TEST_F(WebRtcAudioRendererTest, InitializeWithInvalidDevice) {
mock_sink()->GetOutputDeviceInfo().device_id());
}
-TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceStoppedSource) {
+TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDeviceStoppedSource) {
SetupRenderer(kDefaultOutputDeviceId);
auto* original_sink = mock_sink();
renderer_proxy_->Start();
@@ -410,7 +416,7 @@ TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceStoppedSource) {
renderer_proxy_->Stop();
renderer_proxy_->SwitchOutputDevice(
kInvalidOutputDeviceId,
- base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback,
+ base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback,
base::Unretained(this), &loop));
loop.Run();
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
index f4f9a15db4e..77f65fb2915 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
@@ -6,10 +6,19 @@
#include "base/bind.h"
#include "base/check.h"
-#include "third_party/webrtc/pc/sdp_utils.h"
namespace blink {
+std::unique_ptr<webrtc::SessionDescriptionInterface> CopySessionDescription(
+ const webrtc::SessionDescriptionInterface* description) {
+ if (!description)
+ return nullptr;
+ std::string sdp;
+ description->ToString(&sdp);
+ return std::unique_ptr<webrtc::SessionDescriptionInterface>(
+ webrtc::CreateSessionDescription(description->type(), sdp, nullptr));
+}
+
WebRtcSetDescriptionObserver::States::States()
: signaling_state(
webrtc::PeerConnectionInterface::SignalingState::kClosed) {}
@@ -19,7 +28,9 @@ WebRtcSetDescriptionObserver::States::States(States&& other)
sctp_transport_state(std::move(other.sctp_transport_state)),
transceiver_states(std::move(other.transceiver_states)),
pending_local_description(std::move(other.pending_local_description)),
- current_local_description(std::move(other.current_local_description)) {}
+ current_local_description(std::move(other.current_local_description)),
+ pending_remote_description(std::move(other.pending_remote_description)),
+ current_remote_description(std::move(other.current_remote_description)) {}
WebRtcSetDescriptionObserver::States::~States() = default;
@@ -30,6 +41,8 @@ operator=(States&& other) {
transceiver_states = std::move(other.transceiver_states);
pending_local_description = std::move(other.pending_local_description);
current_local_description = std::move(other.current_local_description);
+ pending_remote_description = std::move(other.pending_remote_description);
+ current_remote_description = std::move(other.current_remote_description);
return *this;
}
@@ -81,22 +94,26 @@ void WebRtcSetDescriptionObserverHandlerImpl::OnSetDescriptionComplete(
transceiver_state_surfacer.Initialize(pc_, track_adapter_map_,
std::move(transceivers));
std::unique_ptr<webrtc::SessionDescriptionInterface>
- pending_local_description = pc_->pending_local_description()
- ? webrtc::CloneSessionDescription(
- pc_->pending_local_description())
- : nullptr;
+ pending_local_description =
+ CopySessionDescription(pc_->pending_local_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_local_description =
+ CopySessionDescription(pc_->current_local_description());
std::unique_ptr<webrtc::SessionDescriptionInterface>
- current_local_description = pc_->current_local_description()
- ? webrtc::CloneSessionDescription(
- pc_->current_local_description())
- : nullptr;
+ pending_remote_description =
+ CopySessionDescription(pc_->pending_remote_description());
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description =
+ CopySessionDescription(pc_->current_remote_description());
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WebRtcSetDescriptionObserverHandlerImpl::
OnSetDescriptionCompleteOnMainThread,
this, std::move(error), pc_->signaling_state(),
std::move(transceiver_state_surfacer),
std::move(pending_local_description),
- std::move(current_local_description)));
+ std::move(current_local_description),
+ std::move(pending_remote_description),
+ std::move(current_remote_description)));
}
void WebRtcSetDescriptionObserverHandlerImpl::
@@ -107,7 +124,11 @@ void WebRtcSetDescriptionObserverHandlerImpl::
std::unique_ptr<webrtc::SessionDescriptionInterface>
pending_local_description,
std::unique_ptr<webrtc::SessionDescriptionInterface>
- current_local_description) {
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description) {
CHECK(main_task_runner_->BelongsToCurrentThread());
WebRtcSetDescriptionObserver::States states;
states.signaling_state = signaling_state;
@@ -116,6 +137,8 @@ void WebRtcSetDescriptionObserverHandlerImpl::
states.transceiver_states = transceiver_state_surfacer.ObtainStates();
states.pending_local_description = std::move(pending_local_description);
states.current_local_description = std::move(current_local_description);
+ states.pending_remote_description = std::move(pending_remote_description);
+ states.current_remote_description = std::move(current_remote_description);
observer_->OnSetDescriptionComplete(std::move(error), std::move(states));
}
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
index a8914d22f4d..196348e231c 100644
--- a/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
+++ b/chromium/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
@@ -30,6 +30,14 @@
namespace blink {
+// Copies the session description.
+// Note: At the time of writing, third_party/webrtc/pc/sdp_utils.h's
+// webrtc::CloneSessionDescription() creates a copy that does not include
+// candidates added with AddIceCandidate. This is why we need our own copy
+// function, which copies everything.
+std::unique_ptr<webrtc::SessionDescriptionInterface> CopySessionDescription(
+ const webrtc::SessionDescriptionInterface* description);
+
// The blink layer correspondent of the setLocalDescription() observer
// (webrtc::SetSessionDescriptionObserver) and setRemoteDescription() observer
// (webrtc::SetRemoteDescriptionObserverInterface). The implementation should
@@ -51,15 +59,14 @@ class MODULES_EXPORT WebRtcSetDescriptionObserver
webrtc::PeerConnectionInterface::SignalingState signaling_state;
blink::WebRTCSctpTransportSnapshot sctp_transport_state;
std::vector<blink::RtpTransceiverState> transceiver_states;
- // For now, the session descriptions are only surfaced for the sake of
- // showing up in chrome://webrtc-internals/ when implicit
- // setLocalDescription() resolves.
- // TODO(https://crbug.com/788558): Surface all states to blink at the same,
- // time, including [current/pending][Local/Remote]Description.
std::unique_ptr<webrtc::SessionDescriptionInterface>
pending_local_description;
std::unique_ptr<webrtc::SessionDescriptionInterface>
current_local_description;
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description;
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description;
DISALLOW_COPY_AND_ASSIGN(States);
};
@@ -117,7 +124,11 @@ class MODULES_EXPORT WebRtcSetDescriptionObserverHandlerImpl
std::unique_ptr<webrtc::SessionDescriptionInterface>
pending_local_description,
std::unique_ptr<webrtc::SessionDescriptionInterface>
- current_local_description);
+ current_local_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ pending_remote_description,
+ std::unique_ptr<webrtc::SessionDescriptionInterface>
+ current_remote_description);
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_;
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 ac228be3839..9b403561415 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
@@ -242,6 +242,7 @@ void PictureInPictureControllerImpl::ExitPictureInPicture(
if (!EnsureService())
return;
+ DCHECK(picture_in_picture_session_.is_bound());
picture_in_picture_session_->Stop(
WTF::Bind(&PictureInPictureControllerImpl::OnExitedPictureInPicture,
WrapPersistent(this), WrapPersistent(resolver)));
diff --git a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.cc b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
index 3a21ecc8f68..db13baf4d19 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
+++ b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/navigator.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/modules/plugins/dom_mime_type.h"
#include "third_party/blink/renderer/modules/plugins/dom_mime_type_array.h"
#include "third_party/blink/renderer/modules/plugins/dom_plugin_array.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
@@ -52,43 +53,80 @@ bool NavigatorPlugins::javaEnabled(Navigator& navigator) {
return false;
}
+namespace {
+
+void RecordPlugins(LocalFrame* frame, DOMPluginArray* plugins) {
+ if (!IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+ WebFeature::kNavigatorPlugins) ||
+ !frame) {
+ return;
+ }
+ if (Document* document = frame->GetDocument()) {
+ IdentifiableTokenBuilder builder;
+ for (unsigned i = 0; i < plugins->length(); i++) {
+ DOMPlugin* plugin = plugins->item(i);
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->name()));
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->description()));
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->filename()));
+ for (unsigned j = 0; j < plugin->length(); j++) {
+ DOMMimeType* mimeType = plugin->item(j);
+ builder.AddToken(IdentifiabilityBenignStringToken(mimeType->type()));
+ builder.AddToken(
+ IdentifiabilityBenignStringToken(mimeType->description()));
+ builder.AddToken(
+ IdentifiabilityBenignStringToken(mimeType->suffixes()));
+ }
+ }
+ IdentifiabilityMetricBuilder(document->UkmSourceID())
+ .SetWebfeature(WebFeature::kNavigatorPlugins, builder.GetToken())
+ .Record(document->UkmRecorder());
+ }
+}
+
+} // namespace
+
DOMPluginArray* NavigatorPlugins::plugins(LocalFrame* frame) const {
if (!plugins_)
plugins_ = MakeGarbageCollected<DOMPluginArray>(frame);
DOMPluginArray* result = plugins_.Get();
- if (!IdentifiabilityStudySettings::Get()->IsActive() || !frame)
- return result;
+ RecordPlugins(frame, result);
+ return result;
+}
+
+DOMMimeTypeArray* NavigatorPlugins::mimeTypes(LocalFrame* frame) const {
+ if (!mime_types_) {
+ mime_types_ = MakeGarbageCollected<DOMMimeTypeArray>(frame);
+ RecordMimeTypes(frame);
+ }
+ return mime_types_.Get();
+}
+
+void NavigatorPlugins::RecordMimeTypes(LocalFrame* frame) const {
+ constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorMimeTypes);
+ if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface) || !frame)
+ return;
Document* document = frame->GetDocument();
if (!document)
- return result;
-
- // Build digest...
+ return;
IdentifiableTokenBuilder builder;
- for (unsigned i = 0; i < result->length(); i++) {
- DOMPlugin* plugin = result->item(i);
- builder.AddToken(IdentifiabilityBenignStringToken(plugin->name()))
- .AddToken(IdentifiabilityBenignStringToken(plugin->description()))
- .AddToken(IdentifiabilityBenignStringToken(plugin->filename()));
- for (unsigned j = 0; j < plugin->length(); j++) {
- DOMMimeType* mimeType = plugin->item(j);
- builder.AddToken(IdentifiabilityBenignStringToken(mimeType->type()))
- .AddToken(IdentifiabilityBenignStringToken(mimeType->description()))
- .AddToken(IdentifiabilityBenignStringToken(mimeType->suffixes()));
+ for (unsigned i = 0; i < mime_types_->length(); i++) {
+ DOMMimeType* mime_type = mime_types_->item(i);
+ builder.AddToken(IdentifiabilityBenignStringToken(mime_type->type()));
+ builder.AddToken(
+ IdentifiabilityBenignStringToken(mime_type->description()));
+ builder.AddToken(IdentifiabilityBenignStringToken(mime_type->suffixes()));
+ DOMPlugin* plugin = mime_type->enabledPlugin();
+ if (plugin) {
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->name()));
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->filename()));
+ builder.AddToken(IdentifiabilityBenignStringToken(plugin->description()));
}
}
- // ...and report to UKM.
IdentifiabilityMetricBuilder(document->UkmSourceID())
- .SetWebfeature(WebFeature::kNavigatorPlugins, builder.GetToken())
+ .Set(surface, builder.GetToken())
.Record(document->UkmRecorder());
-
- return result;
-}
-
-DOMMimeTypeArray* NavigatorPlugins::mimeTypes(LocalFrame* frame) const {
- if (!mime_types_)
- mime_types_ = MakeGarbageCollected<DOMMimeTypeArray>(frame);
- return mime_types_.Get();
}
void NavigatorPlugins::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.h b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.h
index 7f424a4cbdc..e45d7795df2 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.h
+++ b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.h
@@ -35,6 +35,8 @@ class NavigatorPlugins final : public GarbageCollected<NavigatorPlugins>,
DOMPluginArray* plugins(LocalFrame*) const;
DOMMimeTypeArray* mimeTypes(LocalFrame*) const;
+ void RecordMimeTypes(LocalFrame*) const;
+
mutable Member<DOMPluginArray> plugins_;
mutable Member<DOMMimeTypeArray> mime_types_;
};
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 8f7653c109c..8c83f5e4462 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl
+++ b/chromium/third_party/blink/renderer/modules/plugins/navigator_plugins.idl
@@ -8,5 +8,5 @@
] partial interface Navigator {
[HighEntropy, MeasureAs=NavigatorPlugins] readonly attribute PluginArray plugins;
[HighEntropy, MeasureAs=NavigatorMimeTypes] readonly attribute MimeTypeArray mimeTypes;
- boolean javaEnabled();
+ [HighEntropy=Direct, Measure] boolean javaEnabled();
};
diff --git a/chromium/third_party/blink/renderer/modules/plugins/plugin.idl b/chromium/third_party/blink/renderer/modules/plugins/plugin.idl
index f80fcf6c703..dbbbe314320 100644
--- a/chromium/third_party/blink/renderer/modules/plugins/plugin.idl
+++ b/chromium/third_party/blink/renderer/modules/plugins/plugin.idl
@@ -25,9 +25,9 @@
ImplementedAs=DOMPlugin,
LegacyUnenumerableNamedProperties
] interface Plugin {
- readonly attribute DOMString name;
- readonly attribute DOMString filename;
- readonly attribute DOMString description;
+ [HighEntropy=Direct, MeasureAs=PluginName] readonly attribute DOMString name;
+ [HighEntropy=Direct, MeasureAs=PluginFilename] readonly attribute DOMString filename;
+ [HighEntropy=Direct, MeasureAs=PluginDescription] readonly attribute DOMString description;
readonly attribute unsigned long length;
getter MimeType? item(unsigned long index);
getter MimeType? namedItem(DOMString name);
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h
index a5d972c0650..b735fe8fc08 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
@@ -33,9 +34,10 @@ class PresentationReceiver;
class PresentationRequest;
class WebString;
-class PresentationConnection : public EventTargetWithInlineData,
- public ExecutionContextLifecycleStateObserver,
- public mojom::blink::PresentationConnection {
+class MODULES_EXPORT PresentationConnection
+ : public EventTargetWithInlineData,
+ public ExecutionContextLifecycleStateObserver,
+ public mojom::blink::PresentationConnection {
DEFINE_WRAPPERTYPEINFO();
public:
@@ -167,7 +169,8 @@ class PresentationConnection : public EventTargetWithInlineData,
// Represents the controller side of a connection of either a 1-UA or 2-UA
// presentation.
-class ControllerPresentationConnection final : public PresentationConnection {
+class MODULES_EXPORT ControllerPresentationConnection final
+ : public PresentationConnection {
public:
// For CallbackPromiseAdapter.
static ControllerPresentationConnection* Take(
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
index 0dac738c3d5..f890e286ead 100644
--- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
@@ -5,10 +5,12 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONNECTION_CALLBACKS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONNECTION_CALLBACKS_H_
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink-forward.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -24,7 +26,7 @@ class ScriptPromiseResolver;
// ControllerPresentationConnection. In the case of reconnect, the callback may
// take an existing connection object with which the promise will be resolved
// on success.
-class PresentationConnectionCallbacks final {
+class MODULES_EXPORT PresentationConnectionCallbacks final {
USING_FAST_MALLOC(PresentationConnectionCallbacks);
public:
@@ -37,6 +39,11 @@ class PresentationConnectionCallbacks final {
mojom::blink::PresentationErrorPtr);
private:
+ FRIEND_TEST_ALL_PREFIXES(PresentationConnectionCallbacksTest, HandleError);
+ FRIEND_TEST_ALL_PREFIXES(PresentationConnectionCallbacksTest, HandleSuccess);
+ FRIEND_TEST_ALL_PREFIXES(PresentationConnectionCallbacksTest,
+ HandleReconnect);
+
void OnSuccess(const mojom::blink::PresentationInfo&,
mojo::PendingRemote<mojom::blink::PresentationConnection>
connection_remote,
diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc
new file mode 100644
index 00000000000..3f3f49c4e50
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2020 The Chromium Authors. 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/presentation/presentation_connection_callbacks.h"
+
+#include <utility>
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "testing/gmock/include/gmock/gmock.h" // MockFunctionScope
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h" // MockFunctionScope
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h" // MockFunctionScope
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/modules/presentation/presentation_connection.h"
+#include "third_party/blink/renderer/modules/presentation/presentation_request.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h" // MockFunctionScope
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h" // MockFunctionScope
+#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" // MockFunctionScope
+#include "third_party/blink/renderer/platform/wtf/vector.h" // MockFunctionScope
+
+constexpr char kPresentationUrl[] = "https://example.com";
+constexpr char kPresentationId[] = "xyzzy";
+
+namespace blink {
+
+using mojom::blink::PresentationConnectionResult;
+using mojom::blink::PresentationConnectionResultPtr;
+using mojom::blink::PresentationConnectionState;
+using mojom::blink::PresentationError;
+using mojom::blink::PresentationErrorType;
+using mojom::blink::PresentationInfo;
+using mojom::blink::PresentationInfoPtr;
+
+namespace {
+
+// TODO(crbug.com/1120218): Consolidate with PaymentRequestMockFunctionScope and
+// move to shared folder
+class MockFunctionScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit MockFunctionScope(ScriptState* script_state)
+ : script_state_(script_state) {}
+ ~MockFunctionScope() {
+ v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate());
+ for (MockFunction* mock_function : mock_functions_)
+ testing::Mock::VerifyAndClearExpectations(mock_function);
+ }
+
+ v8::Local<v8::Function> ExpectCall() {
+ mock_functions_.push_back(
+ MakeGarbageCollected<MockFunction>(script_state_));
+ EXPECT_CALL(*mock_functions_.back(), Call(testing::_));
+ return mock_functions_.back()->Bind();
+ }
+
+ v8::Local<v8::Function> ExpectNoCall() {
+ mock_functions_.push_back(
+ MakeGarbageCollected<MockFunction>(script_state_));
+ EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0);
+ return mock_functions_.back()->Bind();
+ }
+
+ private:
+ class MockFunction : public ScriptFunction {
+ public:
+ explicit MockFunction(ScriptState* script_state)
+ : ScriptFunction(script_state) {
+ ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>());
+ }
+ v8::Local<v8::Function> Bind() { return BindToV8Function(); }
+ MOCK_METHOD1(Call, ScriptValue(ScriptValue));
+ };
+
+ ScriptState* script_state_;
+ Vector<Persistent<MockFunction>> mock_functions_;
+};
+
+static PresentationRequest* MakeRequest(V8TestingScope* scope) {
+ PresentationRequest* request =
+ PresentationRequest::Create(scope->GetExecutionContext(),
+ kPresentationUrl, scope->GetExceptionState());
+ EXPECT_FALSE(scope->GetExceptionState().HadException());
+ return request;
+}
+
+} // namespace
+
+TEST(PresentationConnectionCallbacksTest, HandleSuccess) {
+ V8TestingScope scope;
+ MockFunctionScope funcs(scope.GetScriptState());
+ auto* resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
+ resolver->Promise().Then(funcs.ExpectCall(), funcs.ExpectNoCall());
+
+ PresentationConnectionCallbacks callbacks(resolver, MakeRequest(&scope));
+
+ // No connection currently exists.
+ EXPECT_FALSE(callbacks.connection_);
+
+ mojo::PendingRemote<mojom::blink::PresentationConnection> connection_remote;
+ mojo::PendingReceiver<mojom::blink::PresentationConnection>
+ connection_receiver = connection_remote.InitWithNewPipeAndPassReceiver();
+ PresentationConnectionResultPtr result = PresentationConnectionResult::New(
+ PresentationInfo::New(url_test_helpers::ToKURL(kPresentationUrl),
+ kPresentationId),
+ std::move(connection_remote), std::move(connection_receiver));
+
+ callbacks.HandlePresentationResponse(std::move(result), nullptr);
+
+ // New connection was created.
+ ControllerPresentationConnection* connection = callbacks.connection_.Get();
+ ASSERT_TRUE(connection);
+ EXPECT_EQ(connection->GetState(), PresentationConnectionState::CONNECTING);
+}
+
+TEST(PresentationConnectionCallbacksTest, HandleReconnect) {
+ V8TestingScope scope;
+ MockFunctionScope funcs(scope.GetScriptState());
+ PresentationInfoPtr info = PresentationInfo::New(
+ url_test_helpers::ToKURL(kPresentationUrl), kPresentationId);
+ auto* resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
+ resolver->Promise().Then(funcs.ExpectCall(), funcs.ExpectNoCall());
+
+ auto* connection = ControllerPresentationConnection::Take(
+ resolver, *info, MakeRequest(&scope));
+ // Connection must be closed for reconnection to succeed.
+ connection->close();
+
+ PresentationConnectionCallbacks callbacks(resolver, connection);
+
+ mojo::PendingRemote<mojom::blink::PresentationConnection> connection_remote;
+ mojo::PendingReceiver<mojom::blink::PresentationConnection>
+ connection_receiver = connection_remote.InitWithNewPipeAndPassReceiver();
+ PresentationConnectionResultPtr result = PresentationConnectionResult::New(
+ std::move(info), std::move(connection_remote),
+ std::move(connection_receiver));
+
+ callbacks.HandlePresentationResponse(std::move(result), nullptr);
+
+ // Previous connection was returned.
+ ControllerPresentationConnection* new_connection =
+ callbacks.connection_.Get();
+ EXPECT_EQ(connection, new_connection);
+ EXPECT_EQ(new_connection->GetState(),
+ PresentationConnectionState::CONNECTING);
+}
+
+TEST(PresentationConnectionCallbacksTest, HandleError) {
+ V8TestingScope scope;
+ MockFunctionScope funcs(scope.GetScriptState());
+ auto* resolver =
+ MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
+ resolver->Promise().Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+
+ PresentationConnectionCallbacks callbacks(resolver, MakeRequest(&scope));
+
+ // No connection currently exists.
+ EXPECT_FALSE(callbacks.connection_);
+
+ callbacks.HandlePresentationResponse(
+ nullptr,
+ PresentationError::New(PresentationErrorType::NO_PRESENTATION_FOUND,
+ "Something bad happened"));
+
+ // No connection was created.
+ EXPECT_FALSE(callbacks.connection_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/BUILD.gn b/chromium/third_party/blink/renderer/modules/push_messaging/BUILD.gn
index 27c9ab2f9c9..4ac672aec28 100644
--- a/chromium/third_party/blink/renderer/modules/push_messaging/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/push_messaging/BUILD.gn
@@ -39,6 +39,5 @@ blink_modules_sources("push_messaging") {
deps = [
"//third_party/blink/renderer/modules/manifest",
"//third_party/blink/renderer/modules/permissions",
- "//third_party/blink/renderer/modules/service_worker",
]
}
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 ede1aa2fc7f..8ec54a602fb 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
@@ -8,7 +8,7 @@
Exposed=(Window,Worker),
RuntimeEnabled=PushMessaging
] interface PushManager {
- [SameObject, SaveSameObject]
+ [SameObject, SaveSameObject, HighEntropy=Direct, Measure]
static readonly attribute FrozenArray<DOMString> supportedContentEncodings;
[CallWith=ScriptState, RaisesException] Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options = {});
diff --git a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
index dfc73c587bd..606b038f64d 100644
--- a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
+++ b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
@@ -24,7 +24,7 @@
*/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DeprecatedStorageInfo {
const unsigned short TEMPORARY = 0;
const unsigned short PERSISTENT = 1;
diff --git a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.idl b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.idl
index 10d3da8df2b..74b0f809e3b 100644
--- a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.idl
+++ b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.idl
@@ -24,7 +24,7 @@
*/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface DeprecatedStorageQuota {
// TODO(crbug.com/841185): |errorCallback| is not nullable in the spec.
[Measure, CallWith=ScriptState] void queryUsageAndQuota(StorageUsageCallback usageCallback, optional StorageErrorCallback? errorCallback);
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/idls.gni b/chromium/third_party/blink/renderer/modules/sanitizer_api/idls.gni
index fdebecb5ca8..c21c59f0833 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/idls.gni
@@ -3,3 +3,5 @@
# found in the LICENSE file.
modules_idl_files = [ "sanitizer.idl" ]
+
+modules_dictionary_idl_files = [ "sanitizer_config.idl" ]
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
index 5de1d5ed11c..ae9c6c0dcf7 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
@@ -4,21 +4,98 @@
#include "sanitizer.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_node_filter.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
+#include "third_party/blink/renderer/core/dom/document_fragment.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/editing/serializers/serialization.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/platform/bindings/exception_messages.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/wtf/vector.h"
namespace blink {
-Sanitizer* Sanitizer::Create(ExceptionState& exception_state) {
- return MakeGarbageCollected<Sanitizer>();
+Sanitizer* Sanitizer::Create(const SanitizerConfig* config,
+ ExceptionState& exception_state) {
+ return MakeGarbageCollected<Sanitizer>(config);
}
-Sanitizer::Sanitizer() = default;
+Sanitizer::Sanitizer(const SanitizerConfig* config)
+ : config_(const_cast<SanitizerConfig*>(config)) {
+ // Format dropElements to uppercases.
+ if (config->hasDropElementsNonNull()) {
+ Vector<String> l;
+ for (const String& s : config->dropElementsNonNull()) {
+ l.push_back(s.UpperASCII());
+ }
+ config_->setDropElements(l);
+ }
+}
Sanitizer::~Sanitizer() = default;
-String Sanitizer::saneStringFrom(const String& input) {
- String sanitizedString = input;
- return sanitizedString;
+String Sanitizer::sanitizeToString(ScriptState* script_state,
+ const String& input,
+ ExceptionState& exception_state) {
+ return CreateMarkup(sanitize(script_state, input, exception_state),
+ kChildrenOnly);
+}
+
+DocumentFragment* Sanitizer::sanitize(ScriptState* script_state,
+ const String& input,
+ ExceptionState& exception_state) {
+ LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+ if (!window) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "Cannot find current DOM window.");
+ return nullptr;
+ }
+ Document* document = window->document();
+ DocumentFragment* fragment = document->createDocumentFragment();
+ DCHECK(document->QuerySelector("body"));
+ fragment->ParseHTML(input, document->QuerySelector("body"));
+
+ // Remove all the elements in the dropElements list.
+ if (config_->hasDropElementsNonNull()) {
+ Node* node = fragment->firstChild();
+
+ while (node) {
+ // Skip non-Element nodes.
+ if (node->getNodeType() != Node::NodeType::kElementNode) {
+ node = NodeTraversal::Next(*node, fragment);
+ continue;
+ }
+
+ // TODO(crbug.com/1126936): Review the sanitising algorithm for non-HTMLs.
+ String node_name = node->nodeName();
+ // If the current element is dropped, remove current element entirely and
+ // proceed to its next sibling.
+ if (config_->dropElementsNonNull().Contains(node_name.UpperASCII())) {
+ Node* tmp = node;
+ node = NodeTraversal::NextSkippingChildren(*node, fragment);
+ tmp->remove();
+ } else {
+ // Otherwise, proceed to the next node (preorder, depth-first
+ // traversal).
+ node = NodeTraversal::Next(*node, fragment);
+ }
+ }
+ }
+
+ return fragment;
+}
+
+// TODO(lyf): https://github.com/WICG/sanitizer-api/issues/34
+SanitizerConfig* Sanitizer::creationOptions() const {
+ return config_;
+}
+
+void Sanitizer::Trace(Visitor* visitor) const {
+ ScriptWrappable::Trace(visitor);
+ visitor->Trace(config_);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
index 6b891945300..3d3144ccdb8 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
@@ -11,17 +11,30 @@
namespace blink {
+class DocumentFragment;
class ExceptionState;
+class SanitizerConfig;
+class ScriptState;
class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- static Sanitizer* Create(ExceptionState&);
- Sanitizer();
+ static Sanitizer* Create(const SanitizerConfig*, ExceptionState&);
+ explicit Sanitizer(const SanitizerConfig*);
~Sanitizer() override;
- String saneStringFrom(const String&);
+ String sanitizeToString(ScriptState*, const String&, ExceptionState&);
+ DocumentFragment* sanitize(ScriptState*, const String&, ExceptionState&);
+
+ SanitizerConfig* creationOptions() const;
+
+ void Trace(Visitor*) const override;
+
+ private:
+ // TODO(lyf): Make config_ read-only. The creationOptions getter which
+ // asks for the pointer is forbidened by a read-only variable.
+ Member<SanitizerConfig> config_ = {};
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
index 0bcac686b73..e8bf834ed90 100644
--- a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
@@ -8,6 +8,9 @@
Exposed=Window,
RuntimeEnabled=SanitizerAPI
] interface Sanitizer {
- [RaisesException] constructor();
- DOMString saneStringFrom(DOMString input);
+ [RaisesException] constructor(optional SanitizerConfig config = {});
+ [CallWith=ScriptState, RaisesException] DOMString sanitizeToString(DOMString input);
+ [CallWith=ScriptState, RaisesException] DocumentFragment sanitize(DOMString input);
+
+ readonly attribute SanitizerConfig creationOptions;
};
diff --git a/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl
new file mode 100644
index 00000000000..d32c3f51e1b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl
@@ -0,0 +1,9 @@
+// Copyright 2020 The Chromium 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/WICG/sanitizer-api
+
+dictionary SanitizerConfig {
+ sequence<DOMString>? dropElements;
+};
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
index 7a929ead68a..9c1eb780db0 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
@@ -117,16 +117,9 @@ void ScreenOrientationController::UpdateOrientation() {
orientation_->SetAngle(screen_info.orientation_angle);
}
-bool ScreenOrientationController::IsActive() const {
- return orientation_ && screen_orientation_service_.is_bound();
-}
-
-bool ScreenOrientationController::IsVisible() const {
- return GetPage() && GetPage()->IsPageVisible();
-}
-
bool ScreenOrientationController::IsActiveAndVisible() const {
- return IsActive() && IsVisible();
+ return orientation_ && screen_orientation_service_.is_bound() && GetPage() &&
+ GetPage()->IsPageVisible();
}
void ScreenOrientationController::PageVisibilityChanged() {
@@ -151,42 +144,37 @@ void ScreenOrientationController::PageVisibilityChanged() {
}
void ScreenOrientationController::NotifyOrientationChanged() {
- if (!IsVisible() || !GetFrame())
- return;
-
- if (IsActive())
- UpdateOrientation();
-
// Keep track of the frames that need to be notified before notifying the
// current frame as it will prevent side effects from the change event
// handlers.
- HeapVector<Member<LocalFrame>> child_frames;
- for (Frame* child = GetFrame()->Tree().FirstChild(); child;
- child = child->Tree().NextSibling()) {
- if (auto* child_local_frame = DynamicTo<LocalFrame>(child))
- child_frames.push_back(child_local_frame);
+ HeapVector<Member<LocalFrame>> frames;
+ for (Frame* frame = GetFrame(); frame;
+ frame = frame->Tree().TraverseNext(GetFrame())) {
+ if (auto* local_frame = DynamicTo<LocalFrame>(frame))
+ frames.push_back(local_frame);
}
-
- // Notify current orientation object.
- if (IsActive() && orientation_) {
- GetExecutionContext()
- ->GetTaskRunner(TaskType::kMiscPlatformAPI)
- ->PostTask(FROM_HERE,
- WTF::Bind(
- [](ScreenOrientation* orientation) {
- ScopedAllowFullscreen allow_fullscreen(
- ScopedAllowFullscreen::kOrientationChange);
- orientation->DispatchEvent(
- *Event::Create(event_type_names::kChange));
- },
- WrapPersistent(orientation_.Get())));
+ for (LocalFrame* frame : frames) {
+ if (auto* controller = FromIfExists(*frame->DomWindow()))
+ controller->NotifyOrientationChangedInternal();
}
+}
- // ... and child frames.
- for (LocalFrame* child_frame : child_frames) {
- if (auto* controller = FromIfExists(*child_frame->DomWindow()))
- controller->NotifyOrientationChanged();
- }
+void ScreenOrientationController::NotifyOrientationChangedInternal() {
+ if (!IsActiveAndVisible())
+ return;
+
+ UpdateOrientation();
+ GetExecutionContext()
+ ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostTask(FROM_HERE,
+ WTF::Bind(
+ [](ScreenOrientation* orientation) {
+ ScopedAllowFullscreen allow_fullscreen(
+ ScopedAllowFullscreen::kOrientationChange);
+ orientation->DispatchEvent(
+ *Event::Create(event_type_names::kChange));
+ },
+ WrapPersistent(orientation_.Get())));
}
void ScreenOrientationController::SetOrientation(
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h
index 9178cf2145a..b7c0577edd8 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h
@@ -56,6 +56,7 @@ class MODULES_EXPORT ScreenOrientationController final
static mojom::blink::ScreenOrientation ComputeOrientation(const gfx::Rect&,
uint16_t);
+ void NotifyOrientationChangedInternal();
// Inherited from ExecutionContextLifecycleObserver and
// PageVisibilityObserver.
@@ -64,8 +65,6 @@ class MODULES_EXPORT ScreenOrientationController final
void UpdateOrientation();
- bool IsActive() const;
- bool IsVisible() const;
bool IsActiveAndVisible() const;
void OnLockOrientationResult(int, ScreenOrientationLockResult);
diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc
index c517bb200a3..5da6f89afc3 100644
--- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc
+++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/modules/screen_orientation/screen_orientation.h"
#include "third_party/blink/renderer/modules/screen_orientation/web_lock_orientation_callback.h"
@@ -62,8 +63,7 @@ class ScreenOrientationControllerTest : public PageTestBase {
PageTestBase::SetUp(IntSize());
HeapMojoAssociatedRemote<device::mojom::blink::ScreenOrientation>
screen_orientation(GetFrame().DomWindow());
- ignore_result(
- screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting());
+ ignore_result(screen_orientation.BindNewEndpointAndPassDedicatedReceiver());
Controller()->SetScreenOrientationAssociatedRemoteForTests(
std::move(screen_orientation));
}
@@ -254,6 +254,49 @@ TEST_F(ScreenOrientationControllerTest, PageVisibilityCrash) {
To<LocalFrame>(frame->Tree().FirstChild())->DomWindow());
EXPECT_EQ(child_orientation->angle(), 1234);
+ url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
+ web_view_helper.Reset();
+}
+
+TEST_F(ScreenOrientationControllerTest,
+ OrientationChangePropagationToGrandchild) {
+ std::string base_url("http://internal.test/");
+ std::string test_url("page_with_grandchild.html");
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
+ WebString::FromUTF8(test_url));
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
+ WebString::FromUTF8("single_iframe.html"));
+ url_test_helpers::RegisterMockedURLLoadFromBase(
+ WebString::FromUTF8(base_url), test::CoreTestDataPath(),
+ WebString::FromUTF8("visible_iframe.html"));
+
+ frame_test_helpers::WebViewHelper web_view_helper;
+ ScreenInfoWebWidgetClient client;
+ client.SetAngle(1234);
+ web_view_helper.InitializeAndLoad(base_url + test_url, nullptr, nullptr,
+ &client);
+
+ Page* page = web_view_helper.GetWebView()->GetPage();
+ LocalFrame* frame = To<LocalFrame>(page->MainFrame());
+
+ // Fully set up on an orientation and a controller in the main frame and
+ // the grandchild, but not the child.
+ ScreenOrientation::Create(frame->DomWindow());
+ Frame* grandchild = frame->Tree().FirstChild()->Tree().FirstChild();
+ auto* grandchild_orientation =
+ ScreenOrientation::Create(To<LocalFrame>(grandchild)->DomWindow());
+
+ // Update the screen info and ensure it propagated to the grandchild.
+ blink::ScreenInfo screen_info;
+ screen_info.orientation_angle = 90;
+ auto* web_frame_widget_base =
+ static_cast<WebFrameWidgetBase*>(frame->GetWidgetForLocalRoot());
+ web_frame_widget_base->UpdateScreenInfo(screen_info);
+ EXPECT_EQ(grandchild_orientation->angle(), 90);
+
+ url_test_helpers::UnregisterAllURLsAndClearMemoryCache();
web_view_helper.Reset();
}
diff --git a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor_test.cc b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor_test.cc
index fc3eeebed49..ee50257b604 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor_test.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/ambient_light_sensor_test.cc
@@ -81,85 +81,6 @@ TEST(AmbientLightSensorTest, IlluminanceInSensorWithoutReading) {
EXPECT_FALSE(sensor->hasReading());
}
-TEST(AmbientLightSensorTest, IlluminanceRounding) {
- SensorTestContext context;
- NonThrowableExceptionState exception_state;
-
- auto* sensor = AmbientLightSensor::Create(context.GetExecutionContext(),
- exception_state);
- sensor->start();
- SensorTestUtils::WaitForEvent(sensor, event_type_names::kActivate);
- EXPECT_FALSE(sensor->hasReading());
-
- // At this point, we have received an 'activate' event, so the sensor is
- // initialized and it is connected to a SensorProxy that we can retrieve
- // here. We then attach a new SensorProxy::Observer that we use to
- // synchronously wait for OnSensorReadingChanged() to be called. Even though
- // the order that each observer is notified is arbitrary, we know that by the
- // time we get to the next call here all observers will have been called.
- auto* sensor_proxy =
- SensorProviderProxy::From(
- To<LocalDOMWindow>(context.GetExecutionContext()))
- ->GetSensorProxy(device::mojom::blink::SensorType::AMBIENT_LIGHT);
- ASSERT_NE(sensor_proxy, nullptr);
- auto* mock_observer = MakeGarbageCollected<MockSensorProxyObserver>();
- sensor_proxy->AddObserver(mock_observer);
-
- auto* event_counter = MakeGarbageCollected<SensorTestUtils::EventCounter>();
- sensor->addEventListener(event_type_names::kReading, event_counter);
-
- // Go from no reading to 24. This will cause a new "reading" event to be
- // emitted, and the rounding will cause illuminance() to return 0.
- context.sensor_provider()->UpdateAmbientLightSensorData(24);
- mock_observer->WaitForOnSensorReadingChanged();
- SensorTestUtils::WaitForEvent(sensor, event_type_names::kReading);
- EXPECT_EQ(24, sensor->latest_reading_);
- ASSERT_TRUE(sensor->illuminance().has_value());
- EXPECT_EQ(0, sensor->illuminance().value());
-
- // Go from 24 to 35. The difference is not significant enough, so we will not
- // emit any "reading" event or store the new raw reading, as if the new
- // reading had never existed.
- context.sensor_provider()->UpdateAmbientLightSensorData(35);
- mock_observer->WaitForOnSensorReadingChanged();
- EXPECT_EQ(24, sensor->latest_reading_);
- ASSERT_TRUE(sensor->illuminance().has_value());
- EXPECT_EQ(0, sensor->illuminance().value());
-
- // Go from 24 to 49. The difference is significant enough, so we will emit a
- // new "reading" event, update our raw reading and return a rounded value of
- // 50 in illuminance().
- context.sensor_provider()->UpdateAmbientLightSensorData(49);
- mock_observer->WaitForOnSensorReadingChanged();
- SensorTestUtils::WaitForEvent(sensor, event_type_names::kReading);
- EXPECT_EQ(49, sensor->latest_reading_);
- ASSERT_TRUE(sensor->illuminance().has_value());
- EXPECT_EQ(50, sensor->illuminance().value());
-
- // Go from 49 to 35. The difference is not significant enough, so we will not
- // emit any "reading" event or store the new raw reading, as if the new
- // reading had never existed.
- context.sensor_provider()->UpdateAmbientLightSensorData(35);
- mock_observer->WaitForOnSensorReadingChanged();
- EXPECT_EQ(49, sensor->latest_reading_);
- ASSERT_TRUE(sensor->illuminance().has_value());
- EXPECT_EQ(50, sensor->illuminance().value());
-
- // Go from 49 to 24. The difference is significant enough, so we will emit a
- // new "reading" event, update our raw reading and return a rounded value of
- // 0 in illuminance().
- context.sensor_provider()->UpdateAmbientLightSensorData(24);
- mock_observer->WaitForOnSensorReadingChanged();
- SensorTestUtils::WaitForEvent(sensor, event_type_names::kReading);
- EXPECT_EQ(24, sensor->latest_reading_);
- ASSERT_TRUE(sensor->illuminance().has_value());
- EXPECT_EQ(0, sensor->illuminance().value());
-
- // Make sure there were no stray "reading" events besides those we expected
- // above.
- EXPECT_EQ(3U, event_counter->event_count());
-}
-
TEST(AmbientLightSensorTest, PlatformSensorReadingsBeforeActivation) {
SensorTestContext context;
NonThrowableExceptionState exception_state;
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
index 3c05cf3a4c7..89e9e77aa9c 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -263,11 +263,7 @@ void Sensor::Activate() {
DCHECK_EQ(state_, SensorState::kActivating);
InitSensorProxyIfNeeded();
- if (!sensor_proxy_) {
- HandleError(DOMExceptionCode::kInvalidStateError,
- "The Sensor is no longer associated to a frame.");
- return;
- }
+ DCHECK(sensor_proxy_);
if (sensor_proxy_->IsInitialized())
RequestAddConfiguration();
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc
index e8f1c915973..b8c8ccc8f83 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc
@@ -18,7 +18,7 @@ SensorProviderProxy::SensorProviderProxy(LocalDOMWindow& window)
inspector_mode_(false) {}
void SensorProviderProxy::InitializeIfNeeded() {
- if (IsInitialized())
+ if (sensor_provider_.is_bound())
return;
GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
@@ -41,7 +41,6 @@ SensorProviderProxy* SensorProviderProxy::From(LocalDOMWindow* window) {
provider_proxy = MakeGarbageCollected<SensorProviderProxy>(*window);
Supplement<LocalDOMWindow>::ProvideTo(*window, provider_proxy);
}
- provider_proxy->InitializeIfNeeded();
return provider_proxy;
}
@@ -94,4 +93,11 @@ void SensorProviderProxy::RemoveSensorProxy(SensorProxy* proxy) {
sensor_proxies_.erase(proxy);
}
+void SensorProviderProxy::GetSensor(
+ device::mojom::blink::SensorType type,
+ device::mojom::blink::SensorProviderProxy::GetSensorCallback callback) {
+ InitializeIfNeeded();
+ sensor_provider_->GetSensor(type, std::move(callback));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h
index c51f78327cd..4d81cdc7cfd 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h
@@ -34,6 +34,8 @@ class MODULES_EXPORT SensorProviderProxy final
SensorProxy* CreateSensorProxy(device::mojom::blink::SensorType, Page*);
SensorProxy* GetSensorProxy(device::mojom::blink::SensorType);
+ void GetSensor(device::mojom::blink::SensorType,
+ device::mojom::blink::SensorProviderProxy::GetSensorCallback);
void set_inspector_mode(bool flag) { inspector_mode_ = flag; }
bool inspector_mode() const { return inspector_mode_; }
@@ -44,19 +46,13 @@ class MODULES_EXPORT SensorProviderProxy final
friend class SensorProxy;
// For SensorProviderProxy friends' use.
- device::mojom::blink::SensorProvider* sensor_provider() const {
- return sensor_provider_.get();
- }
void RemoveSensorProxy(SensorProxy* proxy);
- using SensorsSet = HeapHashSet<WeakMember<SensorProxy>>;
- const SensorsSet& sensor_proxies() const { return sensor_proxies_; }
// For SensorProviderProxy personal use.
void InitializeIfNeeded();
- bool IsInitialized() const { return sensor_provider_.is_bound(); }
void OnSensorProviderConnectionError();
- SensorsSet sensor_proxies_;
+ HeapHashSet<WeakMember<SensorProxy>> sensor_proxies_;
HeapMojoRemote<device::mojom::blink::SensorProvider,
HeapMojoWrapperMode::kWithoutContextObserver>
sensor_provider_;
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 2de9bc062d8..3241bdaab54 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
@@ -131,8 +131,4 @@ bool SensorProxy::ShouldSuspendUpdates() const {
return !focused_frame_origin->CanAccess(this_origin);
}
-device::mojom::blink::SensorProvider* SensorProxy::sensor_provider() const {
- return provider_->sensor_provider();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.h
index e4026920a01..f19de97a360 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.h
@@ -81,7 +81,7 @@ class MODULES_EXPORT SensorProxy : public GarbageCollected<SensorProxy>,
virtual void Suspend() {}
virtual void Resume() {}
- device::mojom::blink::SensorProvider* sensor_provider() const;
+ SensorProviderProxy* sensor_provider_proxy() const { return provider_; }
device::mojom::blink::SensorType type_;
using ObserversSet = HeapHashSet<WeakMember<Observer>>;
diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
index d5858e24e7d..db6b9d3324c 100644
--- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
@@ -41,15 +41,15 @@ void SensorProxyImpl::Initialize() {
if (state_ != kUninitialized)
return;
- if (!sensor_provider()) {
+ if (!sensor_provider_proxy()) {
HandleSensorError();
return;
}
state_ = kInitializing;
- auto callback =
- WTF::Bind(&SensorProxyImpl::OnSensorCreated, WrapWeakPersistent(this));
- sensor_provider()->GetSensor(type_, std::move(callback));
+ sensor_provider_proxy()->GetSensor(
+ type_,
+ WTF::Bind(&SensorProxyImpl::OnSensorCreated, WrapWeakPersistent(this)));
}
void SensorProxyImpl::AddConfiguration(
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn b/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn
index 2e0e69a9571..4dd7639ea2f 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn
@@ -64,5 +64,17 @@ blink_modules_sources("service_worker") {
public_deps = [ "//third_party/blink/renderer/platform" ]
- deps = [ "//base" ]
+ deps_in_modules = [
+ "//third_party/blink/renderer/modules/background_fetch:background_fetch",
+ "//third_party/blink/renderer/modules/background_sync:background_sync",
+ "//third_party/blink/renderer/modules/cache_storage:cache_storage",
+ "//third_party/blink/renderer/modules/content_index:content_index",
+ "//third_party/blink/renderer/modules/cookie_store:cookie_store",
+ "//third_party/blink/renderer/modules/notifications:notifications",
+ "//third_party/blink/renderer/modules/exported:exported",
+ "//third_party/blink/renderer/modules/payments:payments",
+ "//third_party/blink/renderer/modules/push_messaging:push_messaging",
+ ]
+ deps = [ "//base" ] + deps_in_modules
+ allow_circular_includes_from = deps_in_modules
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc b/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
index fc87af51c4e..04ddb638666 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
@@ -26,6 +26,7 @@ CrossOriginResourcePolicyChecker::CrossOriginResourcePolicyChecker(
bool CrossOriginResourcePolicyChecker::IsBlocked(
const url::Origin& initiator_origin,
network::mojom::RequestMode request_mode,
+ network::mojom::RequestDestination request_destination,
const blink::Response& response) {
if (response.InternalURLList().IsEmpty()) {
// The response is synthesized in the service worker, so it's considered as
@@ -43,7 +44,8 @@ bool CrossOriginResourcePolicyChecker::IsBlocked(
return network::CrossOriginResourcePolicy::IsBlockedByHeaderValue(
response.InternalURLList().back(),
response.InternalURLList().front(), initiator_origin,
- corp_header_value, request_mode, initiator_origin, policy_,
+ corp_header_value, request_mode, initiator_origin,
+ request_destination, policy_,
reporter_ ? reporter_.get() : nullptr)
.has_value();
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h b/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h
index dc73ce1612e..900b1b8afe6 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h
+++ b/chromium/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.h
@@ -37,6 +37,7 @@ class CrossOriginResourcePolicyChecker {
bool IsBlocked(const url::Origin& initiator_origin,
network::mojom::RequestMode request_mode,
+ network::mojom::RequestDestination request_destination,
const Response& response);
base::WeakPtr<CrossOriginResourcePolicyChecker> GetWeakPtr();
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 b7c585ad89b..071f55848fa 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
@@ -312,7 +312,7 @@ void FetchRespondWithObserver::OnResponseFulfilled(
if (corp_checker_ &&
corp_checker_->IsBlocked(
url::Origin::Create(GURL(service_worker_global_scope->Url())),
- request_mode_, *response)) {
+ request_mode_, request_destination_, *response)) {
OnResponseRejected(ServiceWorkerResponseError::kDisallowedByCorp);
return;
}
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 1846f257429..b162f4b2fc4 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
@@ -342,7 +342,7 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker(
mojom::ServiceWorkerUpdateViaCache update_via_cache =
ParseUpdateViaCache(options->updateViaCache());
- base::Optional<mojom::ScriptType> script_type =
+ base::Optional<mojom::blink::ScriptType> script_type =
Script::ParseScriptType(options->type());
DCHECK(script_type);
@@ -579,9 +579,10 @@ ServiceWorkerContainer::GetOrCreateServiceWorkerRegistration(
return registration;
}
+ const int64_t registration_id = info.registration_id;
registration = MakeGarbageCollected<ServiceWorkerRegistration>(
GetSupplementable()->GetExecutionContext(), std::move(info));
- service_worker_registration_objects_.Set(info.registration_id, registration);
+ service_worker_registration_objects_.Set(registration_id, registration);
return registration;
}
@@ -591,9 +592,10 @@ ServiceWorker* ServiceWorkerContainer::GetOrCreateServiceWorker(
return nullptr;
ServiceWorker* worker = service_worker_objects_.at(info.version_id);
if (!worker) {
+ const int64_t version_id = info.version_id;
worker = ServiceWorker::Create(GetSupplementable()->GetExecutionContext(),
std::move(info));
- service_worker_objects_.Set(info.version_id, worker);
+ service_worker_objects_.Set(version_id, worker);
}
return worker;
}
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 9fbb0ab774a..b1e9b67aa62 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
@@ -161,7 +161,7 @@ class NotReachedWebServiceWorkerProvider : public WebServiceWorkerProvider {
void RegisterServiceWorker(
const WebURL& scope,
const WebURL& script_url,
- blink::mojom::ScriptType script_type,
+ blink::mojom::blink::ScriptType script_type,
mojom::ServiceWorkerUpdateViaCache update_via_cache,
const WebFetchClientSettingsObject& fetch_client_settings_object,
std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks)
@@ -276,7 +276,7 @@ class StubWebServiceWorkerProvider {
StubWebServiceWorkerProvider()
: register_call_count_(0),
get_registration_call_count_(0),
- script_type_(mojom::ScriptType::kClassic),
+ script_type_(mojom::blink::ScriptType::kClassic),
update_via_cache_(mojom::ServiceWorkerUpdateViaCache::kImports) {}
// Creates a WebServiceWorkerProvider. This can outlive the
@@ -292,7 +292,7 @@ class StubWebServiceWorkerProvider {
const WebURL& RegisterScriptURL() { return register_script_url_; }
size_t GetRegistrationCallCount() { return get_registration_call_count_; }
const WebURL& GetRegistrationURL() { return get_registration_url_; }
- mojom::ScriptType ScriptType() const { return script_type_; }
+ mojom::blink::ScriptType ScriptType() const { return script_type_; }
mojom::ServiceWorkerUpdateViaCache UpdateViaCache() const {
return update_via_cache_;
}
@@ -308,7 +308,7 @@ class StubWebServiceWorkerProvider {
void RegisterServiceWorker(
const WebURL& scope,
const WebURL& script_url,
- blink::mojom::ScriptType script_type,
+ blink::mojom::blink::ScriptType script_type,
mojom::ServiceWorkerUpdateViaCache update_via_cache,
const WebFetchClientSettingsObject& fetch_client_settings_object,
std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks)
@@ -350,7 +350,7 @@ class StubWebServiceWorkerProvider {
WebURL register_script_url_;
size_t get_registration_call_count_;
WebURL get_registration_url_;
- mojom::ScriptType script_type_;
+ mojom::blink::ScriptType script_type_;
mojom::ServiceWorkerUpdateViaCache update_via_cache_;
};
@@ -375,7 +375,7 @@ TEST_F(ServiceWorkerContainerTest,
stub_provider.RegisterScope());
EXPECT_EQ(WebURL(KURL("http://localhost/x/y/worker.js")),
stub_provider.RegisterScriptURL());
- EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
+ EXPECT_EQ(mojom::blink::ScriptType::kClassic, stub_provider.ScriptType());
EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
stub_provider.UpdateViaCache());
}
@@ -395,7 +395,7 @@ TEST_F(ServiceWorkerContainerTest,
EXPECT_EQ(1ul, stub_provider.GetRegistrationCallCount());
EXPECT_EQ(WebURL(KURL("http://localhost/x/index.html")),
stub_provider.GetRegistrationURL());
- EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
+ EXPECT_EQ(mojom::blink::ScriptType::kClassic, stub_provider.ScriptType());
EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
stub_provider.UpdateViaCache());
}
@@ -422,7 +422,7 @@ TEST_F(ServiceWorkerContainerTest,
stub_provider.RegisterScope());
EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")),
stub_provider.RegisterScriptURL());
- EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType());
+ EXPECT_EQ(mojom::blink::ScriptType::kClassic, stub_provider.ScriptType());
EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kNone,
stub_provider.UpdateViaCache());
}
@@ -448,7 +448,7 @@ TEST_F(ServiceWorkerContainerTest, Register_TypeOptionDelegatesToProvider) {
stub_provider.RegisterScope());
EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")),
stub_provider.RegisterScriptURL());
- EXPECT_EQ(mojom::ScriptType::kModule, stub_provider.ScriptType());
+ EXPECT_EQ(mojom::blink::ScriptType::kModule, stub_provider.ScriptType());
EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
stub_provider.UpdateViaCache());
}
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
index 216260c1748..55a94517315 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
@@ -15,15 +15,19 @@ ServiceWorkerContentSettingsProxy::ServiceWorkerContentSettingsProxy(
ServiceWorkerContentSettingsProxy::~ServiceWorkerContentSettingsProxy() =
default;
-bool ServiceWorkerContentSettingsProxy::RequestFileSystemAccessSync() {
- NOTREACHED();
- return false;
-}
-
-bool ServiceWorkerContentSettingsProxy::AllowIndexedDB() {
+bool ServiceWorkerContentSettingsProxy::AllowStorageAccessSync(
+ StorageType storage_type) {
bool result = false;
- GetService()->AllowIndexedDB(&result);
- return result;
+ if (storage_type == StorageType::kIndexedDB) {
+ GetService()->AllowIndexedDB(&result);
+ return result;
+ } else if (storage_type == StorageType::kFileSystem) {
+ NOTREACHED();
+ return false;
+ } else {
+ // TODO(shuagga@microsoft.com): Revisit this default in the future.
+ return true;
+ }
}
// Use ThreadSpecific to ensure that |content_settings_instance_host| is
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 3835f3fe5a2..4d9514ff93a 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
@@ -29,8 +29,7 @@ class ServiceWorkerContentSettingsProxy final
// WebContentSettingsClient overrides.
// Asks the browser process about the settings.
// Blocks until the response arrives.
- bool RequestFileSystemAccessSync() override;
- bool AllowIndexedDB() override;
+ bool AllowStorageAccessSync(StorageType storage_type) override;
private:
// To ensure the returned pointer is destructed on the same thread
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 d86d690d4c5..d5a1df2fc92 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
@@ -36,6 +36,7 @@
#include "base/bind_helpers.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
@@ -54,16 +55,19 @@
#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/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_event_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_content_index_event_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_notification_event_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_request_event_init.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/execution_context/agent.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fetch/global_fetch.h"
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/inspector/request_debug_header_scope.h"
#include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h"
#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
@@ -353,7 +357,7 @@ ServiceWorkerGlobalScope::GetInstalledScriptsManager() {
void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size,
size_t cached_metadata_size) {
- DCHECK_EQ(GetScriptType(), mojom::ScriptType::kClassic);
+ DCHECK_EQ(GetScriptType(), mojom::blink::ScriptType::kClassic);
base::UmaHistogramCustomCounts(
"ServiceWorker.ScriptSize",
base::saturated_cast<base::Histogram::Sample>(script_size), 1000, 5000000,
@@ -372,7 +376,7 @@ void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size,
void ServiceWorkerGlobalScope::CountImportedScript(
size_t script_size,
size_t cached_metadata_size) {
- DCHECK_EQ(GetScriptType(), mojom::ScriptType::kClassic);
+ DCHECK_EQ(GetScriptType(), mojom::blink::ScriptType::kClassic);
CountScriptInternal(script_size, cached_metadata_size);
}
@@ -385,7 +389,7 @@ void ServiceWorkerGlobalScope::DidEvaluateScript() {
// Skip recording UMAs for module scripts because there're no ways to get the
// number of static-imported scripts and the total size of the imported
// scripts.
- if (GetScriptType() == mojom::ScriptType::kModule) {
+ if (GetScriptType() == mojom::blink::ScriptType::kModule) {
return;
}
@@ -708,8 +712,9 @@ ServiceWorker* ServiceWorkerGlobalScope::GetOrCreateServiceWorker(
return nullptr;
::blink::ServiceWorker* worker = service_worker_objects_.at(info.version_id);
if (!worker) {
+ const int64_t version_id = info.version_id;
worker = ::blink::ServiceWorker::Create(this, std::move(info));
- service_worker_objects_.Set(info.version_id, worker);
+ service_worker_objects_.Set(version_id, worker);
}
return worker;
}
@@ -822,22 +827,29 @@ int ServiceWorkerGlobalScope::GetOutstandingThrottledLimit() const {
return features::kInstallingServiceWorkerOutstandingThrottledLimit.Get();
}
-void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls,
- ExceptionState& exception_state) {
+bool ServiceWorkerGlobalScope::CrossOriginIsolatedCapability() const {
+ // TODO(crbug.com/1131404): Return Agent::IsCrossOriginIsolated().
+ return false;
+}
+
+void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls) {
for (const String& string_url : urls) {
KURL completed_url = CompleteURL(string_url);
if (installed_scripts_manager_ &&
!installed_scripts_manager_->IsScriptInstalled(completed_url)) {
DCHECK(installed_scripts_manager_->IsScriptInstalled(Url()));
- exception_state.ThrowDOMException(
- DOMExceptionCode::kNetworkError,
- "Failed to import '" + completed_url.ElidedString() +
- "'. importScripts() of new scripts after service worker "
- "installation is not allowed.");
+ v8::Isolate* isolate = GetThread()->GetIsolate();
+ V8ThrowException::ThrowException(
+ isolate,
+ V8ThrowDOMException::CreateOrEmpty(
+ isolate, DOMExceptionCode::kNetworkError,
+ "Failed to import '" + completed_url.ElidedString() +
+ "'. importScripts() of new scripts after service worker "
+ "installation is not allowed."));
return;
}
}
- WorkerGlobalScope::importScripts(urls, exception_state);
+ WorkerGlobalScope::importScripts(urls);
}
SingleCachedMetadataHandler*
@@ -894,8 +906,9 @@ void ServiceWorkerGlobalScope::DidHandleInstallEvent(
TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
TRACE_ID_LOCAL(install_event_id)),
TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+ GlobalFetch::ScopedFetcher* fetcher = GlobalFetch::ScopedFetcher::From(*this);
RunEventCallback(&install_event_callbacks_, event_queue_.get(),
- install_event_id, status);
+ install_event_id, status, fetcher->FetchCount());
}
void ServiceWorkerGlobalScope::DidHandleActivateEvent(
@@ -1509,6 +1522,12 @@ void ServiceWorkerGlobalScope::StartFetchEvent(
!params->request->is_main_resource_load ? String() : params->client_id);
event_init->setIsReload(params->request->is_reload);
+ mojom::blink::FetchAPIRequest& fetch_request = *params->request;
+ auto debug_header_it =
+ fetch_request.headers.find(RequestDebugHeaderScope::kHeaderName);
+ auto stack_string = debug_header_it == fetch_request.headers.end()
+ ? String()
+ : debug_header_it->value;
Request* request = Request::Create(
ScriptController()->GetScriptState(), std::move(params->request),
Request::ForServiceWorkerFetchEvent::kTrue);
@@ -1532,6 +1551,7 @@ void ServiceWorkerGlobalScope::StartFetchEvent(
NoteNewFetchEvent(request->url());
+ RequestDebugHeaderScope debug_header_scope(this, stack_string);
DispatchExtendableEventWithRespondWith(fetch_event, wait_until_observer,
respond_with_observer);
}
@@ -1659,7 +1679,20 @@ void ServiceWorkerGlobalScope::DispatchInstallEvent(
event_queue_->EnqueueNormal(
WTF::Bind(&ServiceWorkerGlobalScope::StartInstallEvent,
WrapWeakPersistent(this), std::move(callback)),
- CreateAbortCallback(&install_event_callbacks_), base::nullopt);
+ WTF::Bind(&ServiceWorkerGlobalScope::AbortInstallEvent,
+ WrapWeakPersistent(this)),
+ base::nullopt);
+}
+
+void ServiceWorkerGlobalScope::AbortInstallEvent(
+ int event_id,
+ mojom::blink::ServiceWorkerEventStatus status) {
+ DCHECK(IsContextThread());
+ auto iter = install_event_callbacks_.find(event_id);
+ DCHECK(iter != install_event_callbacks_.end());
+ GlobalFetch::ScopedFetcher* fetcher = GlobalFetch::ScopedFetcher::From(*this);
+ std::move(iter->value).Run(status, fetcher->FetchCount());
+ install_event_callbacks_.erase(iter);
}
void ServiceWorkerGlobalScope::StartInstallEvent(
@@ -1910,6 +1943,11 @@ void ServiceWorkerGlobalScope::DispatchFetchEventForMainResource(
DispatchFetchEventForMainResourceCallback callback) {
DCHECK(IsContextThread());
+ // The timeout for offline events in a service worker. The default value is
+ // the same as the default timeout (5 mins) of all events.
+ static const base::FeatureParam<int> kCustomTimeoutForOfflineEvent{
+ &features::kCheckOfflineCapability, "timeout_second", 5 * 60};
+
// We can use nullptr as a |corp_checker| for the main resource because it
// must be the same origin.
if (params->is_offline_capability_check) {
@@ -1918,7 +1956,8 @@ void ServiceWorkerGlobalScope::DispatchFetchEventForMainResource(
WrapWeakPersistent(this), std::move(params),
/*corp_checker=*/nullptr, std::move(response_callback),
std::move(callback), base::nullopt),
- CreateAbortCallback(&fetch_event_callbacks_), base::nullopt);
+ CreateAbortCallback(&fetch_event_callbacks_),
+ base::TimeDelta::FromSeconds(kCustomTimeoutForOfflineEvent.Get()));
} else {
event_queue_->EnqueueNormal(
WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent,
@@ -2431,9 +2470,8 @@ void ServiceWorkerGlobalScope::NoteRespondedToFetchEvent(
}
void ServiceWorkerGlobalScope::RecordQueuingTime(base::TimeTicks created_time) {
- base::UmaHistogramMediumTimes(
- "ServiceWorker.FetchEvent.QueuingTime",
- base::TimeTicks::Now() - created_time);
+ base::UmaHistogramMediumTimes("ServiceWorker.FetchEvent.QueuingTime",
+ base::TimeTicks::Now() - created_time);
}
} // 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 da50e108d74..bdf80411a04 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
@@ -317,6 +317,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
// Returns the token that uniquely identifies this worker.
const ServiceWorkerToken& GetServiceWorkerToken() const { return token_; }
WorkerToken GetWorkerToken() const final { return token_; }
+ bool CrossOriginIsolatedCapability() const final;
ExecutionContextToken GetExecutionContextToken() const final {
return token_;
}
@@ -339,7 +340,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
const override;
private:
- void importScripts(const Vector<String>& urls, ExceptionState&) override;
+ void importScripts(const Vector<String>& urls) override;
SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
const KURL& script_url,
std::unique_ptr<Vector<uint8_t>> meta_data) override;
@@ -420,6 +421,8 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final
subresource_loader_factories,
mojo::PendingReceiver<mojom::blink::ReportingObserver>) override;
void DispatchInstallEvent(DispatchInstallEventCallback callback) override;
+ void AbortInstallEvent(int event_id,
+ mojom::blink::ServiceWorkerEventStatus status);
void DispatchActivateEvent(DispatchActivateEventCallback callback) override;
void DispatchBackgroundFetchAbortEvent(
mojom::blink::BackgroundFetchRegistrationPtr registration,
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 43bf7342e09..5135b55c077 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
@@ -270,7 +270,7 @@ class WebEmbeddedWorkerImplTest : public testing::Test {
std::move(outside_settings_object));
start_data->script_url = script_url_;
start_data->user_agent = WebString("dummy user agent");
- start_data->script_type = mojom::ScriptType::kClassic;
+ start_data->script_type = mojom::blink::ScriptType::kClassic;
start_data->wait_for_debugger_mode =
WebEmbeddedWorkerStartData::kDontWaitForDebugger;
return start_data;
diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
index 5620c3d0679..e8af125af01 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
@@ -5,10 +5,15 @@
#include "third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.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/shapedetection/barcode_detector.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
namespace blink {
@@ -83,6 +88,18 @@ void BarcodeDetectorStatics::OnEnumerateSupportedFormats(
results.ReserveInitialCapacity(results.size());
for (const auto& format : formats)
results.push_back(BarcodeDetector::BarcodeFormatToString(format));
+ if (IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+ WebFeature::kBarcodeDetector_GetSupportedFormats)) {
+ IdentifiableTokenBuilder builder;
+ for (const auto& format_string : results)
+ builder.AddToken(IdentifiabilityBenignStringToken(format_string));
+
+ ExecutionContext* context = GetSupplementable();
+ IdentifiabilityMetricBuilder(context->UkmSourceID())
+ .SetWebfeature(WebFeature::kBarcodeDetector_GetSupportedFormats,
+ builder.GetToken())
+ .Record(context->UkmRecorder());
+ }
resolver->Resolve(results);
}
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 b08e4aab700..cb8f225eafc 100644
--- a/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
+++ b/chromium/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
@@ -133,7 +133,10 @@ ScriptPromise ShapeDetector::DetectShapesOnImageData(
base::CheckedNumeric<int> allocation_size = image_data->Size().Area() * 4;
CHECK_EQ(allocation_size.ValueOrDefault(0), sk_bitmap.computeByteSize());
- memcpy(sk_bitmap.getPixels(), image_data->data()->Data(),
+ // TODO(crbug.com/1115317): Should be compatible with uint_8, float16 and
+ // float32.
+ memcpy(sk_bitmap.getPixels(),
+ image_data->data().GetAsUint8ClampedArray()->Data(),
sk_bitmap.computeByteSize());
return DoDetect(resolver, std::move(sk_bitmap));
@@ -165,8 +168,10 @@ ScriptPromise ShapeDetector::DetectShapesOnImageElement(
return promise;
}
+ // The call to asLegacyBitmap() below forces a readback so getting SwSkImage
+ // here doesn't readback unnecessarily
const sk_sp<SkImage> sk_image =
- blink_image->PaintImageForCurrentFrame().GetSkImage();
+ blink_image->PaintImageForCurrentFrame().GetSwSkImage();
DCHECK_EQ(img->naturalWidth(), static_cast<unsigned>(sk_image->width()));
DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(sk_image->height()));
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_grammar.idl b/chromium/third_party/blink/renderer/modules/speech/speech_grammar.idl
index 22bdec54b31..0b86587ec5e 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_grammar.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_grammar.idl
@@ -29,7 +29,7 @@
LegacyWindowAlias=webkitSpeechGrammar,
LegacyWindowAlias_Measure,
LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechGrammar {
[Measure] constructor();
[URL,CallWith=ScriptState] attribute DOMString src;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.idl b/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.idl
index 0ca57de48a5..41acd6c6e2e 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.idl
@@ -29,7 +29,7 @@
LegacyWindowAlias=webkitSpeechGrammarList,
LegacyWindowAlias_Measure,
LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechGrammarList {
[Measure] constructor();
readonly attribute unsigned long length;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.idl
index de359f83725..d46ffc53cfb 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.idl
@@ -30,7 +30,7 @@
LegacyWindowAlias=webkitSpeechRecognition,
LegacyWindowAlias_Measure,
LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognition : EventTarget {
[CallWith=ExecutionContext, Measure] constructor();
// recognition parameters
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_alternative.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_alternative.idl
index abb9a82d29f..6195319f6d9 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_alternative.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_alternative.idl
@@ -26,7 +26,7 @@
// https://w3c.github.io/speech-api/#speechrecognitionalternative
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognitionAlternative {
readonly attribute DOMString transcript;
readonly attribute float confidence;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl
index c2bd04e96d9..b75869f0d1a 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl
@@ -29,7 +29,7 @@
LegacyWindowAlias=webkitSpeechRecognitionError,
LegacyWindowAlias_Measure,
LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognitionErrorEvent : Event {
constructor(DOMString type, optional SpeechRecognitionErrorEventInit eventInitDict = {});
readonly attribute DOMString error;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl
index 4150623acc9..812cb323432 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.idl
@@ -29,7 +29,7 @@
LegacyWindowAlias=webkitSpeechRecognitionEvent,
LegacyWindowAlias_Measure,
LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognitionEvent : Event {
constructor(DOMString type, optional SpeechRecognitionEventInit initDict = {});
readonly attribute unsigned long resultIndex;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result.idl
index 1a3b9e48c71..fe37c623092 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result.idl
@@ -26,7 +26,7 @@
// https://w3c.github.io/speech-api/#speechrecognitionresult
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognitionResult {
readonly attribute unsigned long length;
getter SpeechRecognitionAlternative item(unsigned long index);
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result_list.idl b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result_list.idl
index 0f4f73a6d55..c551e2b28b4 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result_list.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_result_list.idl
@@ -26,7 +26,7 @@
// https://w3c.github.io/speech-api/#speechrecognitionresultlist
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechRecognitionResultList {
readonly attribute unsigned long length;
getter SpeechRecognitionResult item(unsigned long index);
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index ff2c4bb83d4..b71fb8bbf5d 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -27,6 +27,10 @@
#include "build/build_config.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_speech_synthesis_error_event_init.h"
@@ -35,12 +39,15 @@
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h"
#include "third_party/blink/renderer/modules/speech/speech_synthesis_event.h"
+#include "third_party/blink/renderer/modules/speech/speech_synthesis_voice.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
namespace blink {
@@ -91,9 +98,32 @@ void SpeechSynthesis::OnSetVoiceList(
const HeapVector<Member<SpeechSynthesisVoice>>& SpeechSynthesis::getVoices() {
// Kick off initialization here to ensure voice list gets populated.
ignore_result(TryEnsureMojomSynthesis());
+ RecordVoicesForIdentifiability();
return voice_list_;
}
+void SpeechSynthesis::RecordVoicesForIdentifiability() const {
+ constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kWebFeature,
+ WebFeature::kSpeechSynthesis_GetVoices_Method);
+ if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface))
+ return;
+ ExecutionContext* context = GetExecutionContext();
+ if (!context)
+ return;
+
+ IdentifiableTokenBuilder builder;
+ for (const auto& voice : voice_list_) {
+ builder.AddToken(IdentifiabilityBenignStringToken(voice->voiceURI()));
+ builder.AddToken(IdentifiabilityBenignStringToken(voice->lang()));
+ builder.AddToken(IdentifiabilityBenignStringToken(voice->name()));
+ builder.AddToken(voice->localService());
+ }
+ IdentifiabilityMetricBuilder(context->UkmSourceID())
+ .Set(surface, builder.GetToken())
+ .Record(context->UkmRecorder());
+}
+
bool SpeechSynthesis::speaking() const {
// If we have a current speech utterance, then that means we're assumed to be
// in a speaking state. This state is independent of whether the utterance
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h
index f5065971e83..025964b05f3 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h
@@ -122,6 +122,8 @@ class MODULES_EXPORT SpeechSynthesis final
bool IsAllowedToStartByAutoplay() const;
+ void RecordVoicesForIdentifiability() const;
+
void SetMojomSynthesisForTesting(
mojo::PendingRemote<mojom::blink::SpeechSynthesis>);
mojom::blink::SpeechSynthesis* TryEnsureMojomSynthesis();
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.idl
index 7d2a878d837..752d1ca3e7a 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.idl
@@ -26,7 +26,7 @@
// https://w3c.github.io/speech-api/#speechsynthesis
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechSynthesis : EventTarget {
readonly attribute boolean pending;
readonly attribute boolean speaking;
diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_voice.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_voice.idl
index c2f90c2e881..6f4bde6d594 100644
--- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_voice.idl
+++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_voice.idl
@@ -26,7 +26,7 @@
// https://w3c.github.io/speech-api/#speechsynthesisvoice
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SpeechSynthesisVoice {
readonly attribute DOMString voiceURI;
readonly attribute DOMString name;
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 6c1590be718..5c5c9209385 100644
--- a/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc
+++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc
@@ -56,8 +56,14 @@ StorageController* StorageController::GetInstance() {
bool StorageController::CanAccessStorageArea(LocalFrame* frame,
StorageArea::StorageType type) {
if (auto* settings_client = frame->GetContentSettingsClient()) {
- return settings_client->AllowStorage(
- type == StorageArea::StorageType::kLocalStorage);
+ switch (type) {
+ case StorageArea::StorageType::kLocalStorage:
+ return settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kLocalStorage);
+ case StorageArea::StorageType::kSessionStorage:
+ return settings_client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kSessionStorage);
+ }
}
return true;
}
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/BUILD.gn b/chromium/third_party/blink/renderer/modules/video_rvfc/BUILD.gn
index 6c561e7dbef..939db9a9b23 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/BUILD.gn
@@ -11,4 +11,6 @@ blink_modules_sources("video_rvfc") {
"video_frame_request_callback_collection.cc",
"video_frame_request_callback_collection.h",
]
+
+ deps = [ "//third_party/blink/renderer/modules/xr:xr" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
index 705c03abd6c..5bff0af774e 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
@@ -16,6 +16,10 @@
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/core/timing/time_clamper.h"
#include "third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h"
+#include "third_party/blink/renderer/modules/xr/navigator_xr.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
+#include "third_party/blink/renderer/modules/xr/xr_session.h"
+#include "third_party/blink/renderer/modules/xr/xr_system.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -44,6 +48,8 @@ VideoFrameCallbackRequesterImpl::VideoFrameCallbackRequesterImpl(
MakeGarbageCollected<VideoFrameRequestCallbackCollection>(
element.GetExecutionContext())) {}
+VideoFrameCallbackRequesterImpl::~VideoFrameCallbackRequesterImpl() = default;
+
// static
VideoFrameCallbackRequesterImpl& VideoFrameCallbackRequesterImpl::From(
HTMLVideoElement& element) {
@@ -80,21 +86,96 @@ void VideoFrameCallbackRequesterImpl::OnWebMediaPlayerCreated() {
GetSupplementable()->GetWebMediaPlayer()->RequestVideoFrameCallback();
}
-void VideoFrameCallbackRequesterImpl::ScheduleCallbackExecution() {
- TRACE_EVENT1("blink",
- "VideoFrameCallbackRequesterImpl::ScheduleCallbackExecution",
+void VideoFrameCallbackRequesterImpl::ScheduleWindowRaf() {
+ GetSupplementable()
+ ->GetDocument()
+ .GetScriptedAnimationController()
+ .ScheduleVideoFrameCallbacksExecution(
+ WTF::Bind(&VideoFrameCallbackRequesterImpl::OnExecution,
+ WrapWeakPersistent(this)));
+}
+
+void VideoFrameCallbackRequesterImpl::ScheduleExecution() {
+ TRACE_EVENT1("blink", "VideoFrameCallbackRequesterImpl::ScheduleExecution",
"did_schedule", !pending_execution_);
if (pending_execution_)
return;
pending_execution_ = true;
- GetSupplementable()
- ->GetDocument()
- .GetScriptedAnimationController()
- .ScheduleVideoFrameCallbacksExecution(
- WTF::Bind(&VideoFrameCallbackRequesterImpl::OnRenderingSteps,
- WrapWeakPersistent(this)));
+
+ if (TryScheduleImmersiveXRSessionRaf())
+ return;
+
+ ScheduleWindowRaf();
+}
+
+void VideoFrameCallbackRequesterImpl::OnImmersiveSessionStart() {
+ in_immersive_session_ = true;
+
+ if (pending_execution_ && !callback_collection_->IsEmpty())
+ TryScheduleImmersiveXRSessionRaf();
+}
+
+void VideoFrameCallbackRequesterImpl::OnImmersiveSessionEnd() {
+ in_immersive_session_ = false;
+
+ if (pending_execution_ && !callback_collection_->IsEmpty())
+ ScheduleWindowRaf();
+}
+
+void VideoFrameCallbackRequesterImpl::OnImmersiveFrame() {
+ if (callback_collection_->IsEmpty())
+ return;
+
+ if (auto* player = GetSupplementable()->GetWebMediaPlayer())
+ player->UpdateFrameIfStale();
+}
+
+XRFrameProvider* VideoFrameCallbackRequesterImpl::GetXRFrameProvider() {
+ auto& document = GetSupplementable()->GetDocument();
+
+ // Do not force the lazy creation of the NavigatorXR by accessing it through
+ // NavigatorXR::From(). If it doesn't exist already exist, the webpage isn't
+ // using XR.
+ if (!NavigatorXR::AlreadyExists(document))
+ return nullptr;
+
+ auto* system = NavigatorXR::From(document)->xr();
+
+ if (!system)
+ return nullptr;
+
+ return system->frameProvider();
+}
+
+bool VideoFrameCallbackRequesterImpl::TryScheduleImmersiveXRSessionRaf() {
+ // Nothing to do here, we will be notified via OnImmersiveSessionStart() when
+ // a new immersive session starts.
+ if (observing_immersive_session_ && !in_immersive_session_)
+ return false;
+
+ auto* frame_provider = GetXRFrameProvider();
+
+ if (!frame_provider)
+ return false;
+
+ if (!observing_immersive_session_) {
+ frame_provider->AddImmersiveSessionObserver(this);
+ observing_immersive_session_ = true;
+ }
+
+ XRSession* session = frame_provider->immersive_session();
+
+ in_immersive_session_ = session && !session->ended();
+
+ if (!in_immersive_session_)
+ return false;
+
+ session->ScheduleVideoFrameCallbacksExecution(WTF::Bind(
+ &VideoFrameCallbackRequesterImpl::OnExecution, WrapWeakPersistent(this)));
+
+ return true;
}
void VideoFrameCallbackRequesterImpl::OnRequestVideoFrameCallback() {
@@ -107,7 +188,7 @@ void VideoFrameCallbackRequesterImpl::OnRequestVideoFrameCallback() {
if (callback_collection_->IsEmpty())
return;
- ScheduleCallbackExecution();
+ ScheduleExecution();
}
void VideoFrameCallbackRequesterImpl::ExecuteVideoFrameCallbacks(
@@ -165,15 +246,15 @@ void VideoFrameCallbackRequesterImpl::ExecuteVideoFrameCallbacks(
callback_collection_->ExecuteFrameCallbacks(high_res_now_ms, metadata);
}
-void VideoFrameCallbackRequesterImpl::OnRenderingSteps(double high_res_now_ms) {
- DCHECK(pending_execution_);
+void VideoFrameCallbackRequesterImpl::OnExecution(double high_res_now_ms) {
TRACE_EVENT1("blink", "VideoFrameCallbackRequesterImpl::OnRenderingSteps",
"has_callbacks", !callback_collection_->IsEmpty());
-
pending_execution_ = false;
// Callbacks could have been canceled from the time we scheduled their
// execution.
+ // We could also be executing a leftover callback scheduled through the
+ // ScriptedAnimationController, right after exiting an immersive XR session.
if (callback_collection_->IsEmpty())
return;
@@ -204,7 +285,7 @@ void VideoFrameCallbackRequesterImpl::OnRenderingSteps(double high_res_now_ms) {
// extra rendering steps would be wasteful.
if (is_hfr && !callback_collection_->IsEmpty() &&
consecutive_stale_frames_ < 2) {
- ScheduleCallbackExecution();
+ ScheduleExecution();
}
}
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h
index 8fae25a78fc..e380eb893ca 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.h
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/html/media/video_frame_callback_requester.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection.h"
+#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/supplementable.h"
@@ -19,7 +20,8 @@ class HTMLVideoElement;
// Implementation of the <video>.requestVideoFrameCallback() API.
// Extends HTMLVideoElement via the VideoFrameCallbackRequester interface.
class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
- : public VideoFrameCallbackRequester {
+ : public VideoFrameCallbackRequester,
+ public XRFrameProvider::ImmersiveSessionObserver {
public:
static VideoFrameCallbackRequesterImpl& From(HTMLVideoElement&);
@@ -29,7 +31,7 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
static void cancelVideoFrameCallback(HTMLVideoElement&, int);
explicit VideoFrameCallbackRequesterImpl(HTMLVideoElement&);
- ~VideoFrameCallbackRequesterImpl() override = default;
+ ~VideoFrameCallbackRequesterImpl() override;
void Trace(Visitor*) const override;
@@ -40,8 +42,13 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
void OnRequestVideoFrameCallback() override;
// Called by ScriptedAnimationController as part of the rendering steps,
- // right before the execution of window.rAF callbacks.
- void OnRenderingSteps(double high_res_now_ms);
+ // right before executing window.rAF callbacks. Also called by OnXRFrame().
+ void OnExecution(double high_res_now_ms);
+
+ // XRFrameProvider::ImmersiveSessionObserver implementation.
+ void OnImmersiveSessionStart() override;
+ void OnImmersiveSessionEnd() override;
+ void OnImmersiveFrame() override;
private:
friend class VideoFrameCallbackRequesterImplTest;
@@ -60,10 +67,23 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
void RegisterCallbackForTest(
VideoFrameRequestCallbackCollection::VideoFrameCallback*);
- // Adds |this| to the ScriptedAnimationController's queue of video.rAF
+ // Queues up |callback_collection_| to be run before the next window.rAF, or
+ // xr_session.rAF if we are an immersive XR session.
+ void ScheduleExecution();
+
+ // Adds |this| to the ScriptedAnimationController's queue of video.rVFC
// callbacks that should be executed during the next rendering steps.
// Also causes rendering steps to be scheduled if needed.
- void ScheduleCallbackExecution();
+ void ScheduleWindowRaf();
+
+ // Check whether there is an immersive XR session, and adds |this| to the list
+ // of video.rVFC callbacks that should be run the next time there is an XR
+ // frame. Requests a new XR frame if needed.
+ // Returns true if we scheduled ourselves, false if there is no immersive XR
+ // session.
+ bool TryScheduleImmersiveXRSessionRaf();
+
+ XRFrameProvider* GetXRFrameProvider();
// Used to keep track of whether or not we have already scheduled a call to
// ExecuteFrameCallbacks() in the next rendering steps.
@@ -81,6 +101,13 @@ class MODULES_EXPORT VideoFrameCallbackRequesterImpl final
// getting new frames.
int consecutive_stale_frames_ = 0;
+ // Indicates whether or not we have registered ourselves with the XR Frame
+ // provider to be notified of immersive XR session events.
+ bool observing_immersive_session_ = false;
+
+ // Indicates if we are currently in an XR session.
+ bool in_immersive_session_ = false;
+
Member<VideoFrameRequestCallbackCollection> callback_collection_;
DISALLOW_COPY_AND_ASSIGN(VideoFrameCallbackRequesterImpl);
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
index c8b7a2ccb66..93b74840c4d 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
@@ -32,6 +32,7 @@ namespace {
class MockWebMediaPlayer : public EmptyWebMediaPlayer {
public:
+ MOCK_METHOD0(UpdateFrameIfStale, void());
MOCK_METHOD0(RequestVideoFrameCallback, void());
MOCK_METHOD0(GetVideoFramePresentationMetadata,
std::unique_ptr<VideoFramePresentationMetadata>());
@@ -58,12 +59,10 @@ class MockFunction : public ScriptFunction {
class MetadataHelper {
public:
static VideoFramePresentationMetadata* GetDefaultMedatada() {
- DCHECK(initialized);
return &metadata_;
}
static std::unique_ptr<VideoFramePresentationMetadata> CopyDefaultMedatada() {
- DCHECK(initialized);
auto copy = std::make_unique<VideoFramePresentationMetadata>();
copy->presented_frames = metadata_.presented_frames;
@@ -77,10 +76,10 @@ class MetadataHelper {
return copy;
}
- static void InitializeFields(base::TimeTicks now) {
- if (initialized)
- return;
-
+ // This method should be called by each test, passing in its own
+ // DocumentLoadTiming::ReferenceMonotonicTime(). Otherwise, we will run into
+ // clamping verification test issues, as described below.
+ static void ReinitializeFields(base::TimeTicks now) {
// We don't want any time ticks be a multiple of 5us, otherwise, we couldn't
// tell whether or not the implementation clamped their values. Therefore,
// we manually set the values for a deterministic test, and make sure we
@@ -101,16 +100,12 @@ class MetadataHelper {
metadata_.metadata.receive_time =
now + base::TimeDelta::FromMillisecondsD(17.1234);
metadata_.metadata.rtp_timestamp = 12345;
-
- initialized = true;
}
private:
- static bool initialized;
static VideoFramePresentationMetadata metadata_;
};
-bool MetadataHelper::initialized = false;
VideoFramePresentationMetadata MetadataHelper::metadata_;
// Helper class that compares the parameters used when invoking a callback, with
@@ -326,9 +321,9 @@ TEST_F(VideoFrameCallbackRequesterImplTest,
testing::Mock::VerifyAndClear(function);
}
-TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters) {
+TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters_WindowRaf) {
auto timing = GetDocument().Loader()->GetTiming();
- MetadataHelper::InitializeFields(timing.ReferenceMonotonicTime());
+ MetadataHelper::ReinitializeFields(timing.ReferenceMonotonicTime());
auto* callback =
MakeGarbageCollected<VfcRequesterParameterVerifierCallback>(timing);
@@ -345,7 +340,7 @@ TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters) {
// Run the callbacks directly, since they weren't scheduled to be run by the
// ScriptedAnimationController.
- vfc_requester().OnRenderingSteps(now_ms);
+ vfc_requester().OnExecution(now_ms);
EXPECT_EQ(callback->last_now(), now_ms);
EXPECT_TRUE(callback->was_invoked());
@@ -353,6 +348,29 @@ TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters) {
testing::Mock::VerifyAndClear(media_player());
}
+TEST_F(VideoFrameCallbackRequesterImplTest, OnXrFrameData) {
+ V8TestingScope scope;
+
+ // New immersive frames should not drive frame updates if we don't have any
+ // pending callbacks.
+ EXPECT_CALL(*media_player(), UpdateFrameIfStale()).Times(0);
+
+ vfc_requester().OnImmersiveFrame();
+
+ testing::Mock::VerifyAndClear(media_player());
+
+ auto* function = MockFunction::Create(scope.GetScriptState());
+ vfc_requester().requestVideoFrameCallback(GetCallback(function));
+
+ // Immersive frames should trigger video frame updates when there are pending
+ // callbacks.
+ EXPECT_CALL(*media_player(), UpdateFrameIfStale());
+
+ vfc_requester().OnImmersiveFrame();
+
+ testing::Mock::VerifyAndClear(media_player());
+}
+
TEST_F(VideoFrameCallbackRequesterImplNullMediaPlayerTest, VerifyNoCrash) {
V8TestingScope scope;
diff --git a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection_test.cc b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection_test.cc
index df0b3e7246b..07be13663d9 100644
--- a/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection_test.cc
+++ b/chromium/third_party/blink/renderer/modules/video_rvfc/video_frame_request_callback_collection_test.cc
@@ -128,8 +128,7 @@ TEST_F(VideoFrameRequestCallbackCollectionTest, CreateCallbackDuringExecution) {
EXPECT_TRUE(collection()->IsEmpty());
}
-TEST_F(VideoFrameRequestCallbackCollectionTest,
- CancelCallbgitackDuringExecution) {
+TEST_F(VideoFrameRequestCallbackCollectionTest, CancelCallbackDuringExecution) {
auto dummy_callback = CreateCallback();
CallbackId dummy_callback_id =
collection()->RegisterFrameCallback(dummy_callback.Get());
diff --git a/chromium/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc b/chromium/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
index 1d29353aad8..c2681add45e 100644
--- a/chromium/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
+++ b/chromium/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
@@ -77,6 +77,12 @@ void VirtualKeyboard::VirtualKeyboardOverlayChanged(
vars.SetVariable(
UADefinedVariable::kKeyboardInsetRight,
StyleEnvironmentVariables::FormatPx(keyboard_rect.right()));
+ vars.SetVariable(
+ UADefinedVariable::kKeyboardInsetWidth,
+ StyleEnvironmentVariables::FormatPx(keyboard_rect.width()));
+ vars.SetVariable(
+ UADefinedVariable::kKeyboardInsetHeight,
+ StyleEnvironmentVariables::FormatPx(keyboard_rect.height()));
}
DispatchEvent(*(MakeGarbageCollected<VirtualKeyboardGeometryChangeEvent>(
event_type_names::kGeometrychange, bounding_rect_)));
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/README.md b/chromium/third_party/blink/renderer/modules/wake_lock/README.md
index bcc41ea6157..94f3543cc89 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/README.md
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/README.md
@@ -37,9 +37,9 @@ The rest of the implementation is found in the following directories:
* `chrome/browser/wake_lock` contains the Chrome-specific side of permission management for Wake Locks. When the Blink implementation needs to either query or request permission for wake locks, the request bubbles up to this directory, where the decision is made based on the wake lock type (for testing purposes, `content_shell` always grants screen wake locks and denies system wake locks in [`shell_permission_manager.cc`](/content/shell/browser/web_test/web_test_message_filter.cc)).
[Mojo interfaces]: ../../../../../services/device/public/mojom/
-[Wake Lock management]: https://w3c.github.io/wake-lock/#managing-wake-locks
-[Wake Lock specification]: https://w3c.github.io/wake-lock/
-[state records]: https://w3c.github.io/wake-lock/#dfn-state-record
+[Wake Lock management]: https://w3c.github.io/screen-wake-lock/#managing-wake-locks
+[Wake Lock specification]: https://w3c.github.io/screen-wake-lock/
+[state records]: https://w3c.github.io/screen-wake-lock/#dfn-state-record
### Testing
@@ -65,7 +65,7 @@ This section describes how the classes described above interact when the followi
const lock = await navigator.wakeLock.request("screen");
```
-1. `WakeLock::request()` performs all the validation steps described in [the spec](https://w3c.github.io/wake-lock/#the-request-method). If all checks have passed, it creates a `ScriptPromiseResolver` and calls `WakeLock::DoRequest()`.
+1. `WakeLock::request()` performs all the validation steps described in [the spec](https://w3c.github.io/screen-wake-lock/#the-request-method). If all checks have passed, it creates a `ScriptPromiseResolver` and calls `WakeLock::DoRequest()`.
1. `WakeLock::DoRequest()` simply forwards its arguments to `WakeLock::ObtainPermission()`. It exists as a separate method just to make writing unit tests easier, as we'd otherwise be unable to use our own `ScriptPromiseResolver`s in tests.
1. `WakeLock::ObtainPermission()` connects to the [permission service](../../../public/mojom/permissions/permission.mojom) and asynchronously requests permission for a screen wake lock.
1. In the browser process, the permission request bubbles up through `//content` and reaches `//chrome`'s [`WakeLockPermissionContext`](/chrome/browser/wake_lock/wake_lock_permission_context.cc), where `WakeLockPermissionContext::GetPermissionStatusInternal()` always grants `CONTENT_SETTINGS_TYPE_WAKE_LOCK_SCREEN` permission requests.
@@ -74,7 +74,7 @@ const lock = await navigator.wakeLock.request("screen");
1. `WakeLockManager::AcquireWakeLock()` creates a new `WakeLockSentinel` instance, passing `this` as the `WakeLockSentinel`'s `WakeLockManager`. This new `WakeLockSentinel` is added to its set of [active locks].
1. The `ScriptPromiseResolver` created by `WakeLock::request()` is resolved with the new `WakeLockSentinel` object.
-[active locks]: https://w3c.github.io/wake-lock/#dfn-activelocks
+[active locks]: https://w3c.github.io/screen-wake-lock/#dfn-activelocks
### Wake Lock cancellation
@@ -94,7 +94,7 @@ This section describes what happens when `lock.release()` is called.
1. `WakeLockManager::UnregisterSentinel()` implements the spec's [release wake lock algorithm]. If the given `WakeLockSentinel` is in `WakeLockManager`'s `wake_lock_sentinels_`, it will be removed and, if the list is empty, `WakeLockManager` will communicate with its `device::mojom::blink::WakeLock` instance and call its `CancelWakeLock()` method.
1. Back in `WakeLockSentinel::DoRelease()`, it then clears its `manager_` member, and dispatches a `release` event with itself as a target.
-[release wake lock algorithm]: https://w3c.github.io/wake-lock/#release-wake-lock-algorithm
+[release wake lock algorithm]: https://w3c.github.io/screen-wake-lock/#release-wake-lock-algorithm
## Other Wake Lock usage in Chromium
@@ -131,7 +131,7 @@ Example usage outside Blink includes:
## Permission Model
-The Wake Lock API spec checks for user activation in the context of [wake lock permission requests](https://w3c.github.io/wake-lock/#dfn-obtain-permission), as a result of a call to `WakeLock.request()`. If a user agent is configured to prompt a user when a wake lock is requested, user activation is required, otherwise the request will be denied.
+The Wake Lock API spec checks for user activation in the context of [wake lock permission requests](https://w3c.github.io/screen-wake-lock/#dfn-obtain-permission), as a result of a call to `WakeLock.request()`. If a user agent is configured to prompt a user when a wake lock is requested, user activation is required, otherwise the request will be denied.
In the Chromium implementation, there currently is no "prompt" state, and no permission UI or settings: wake lock requests are either always granted or always denied:
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 6686d627aaa..48ecc6d2b4b 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
@@ -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://w3c.github.io/wake-lock/#extensions-to-the-navigator-interface
+// https://w3c.github.io/screen-wake-lock/#extensions-to-the-navigator-interface
[
ImplementedAs=NavigatorWakeLock,
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 5ef879f4ec9..cb0c5f1927b 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
@@ -61,7 +61,7 @@ ScriptPromise WakeLock::request(ScriptState* script_state,
return ScriptPromise();
}
- // https://w3c.github.io/wake-lock/#the-request-method
+ // https://w3c.github.io/screen-wake-lock/#the-request-method
auto* context = ExecutionContext::From(script_state);
DCHECK(context->IsWindow() || context->IsDedicatedWorkerGlobalScope());
@@ -162,7 +162,7 @@ ScriptPromise WakeLock::request(ScriptState* script_state,
}
void WakeLock::DoRequest(WakeLockType type, ScriptPromiseResolver* resolver) {
- // https://w3c.github.io/wake-lock/#the-request-method
+ // https://w3c.github.io/screen-wake-lock/#the-request-method
// 5.1. Let state be the result of awaiting obtain permission steps with type:
ObtainPermission(
type, WTF::Bind(&WakeLock::DidReceivePermissionResponse,
@@ -172,7 +172,7 @@ void WakeLock::DoRequest(WakeLockType type, ScriptPromiseResolver* resolver) {
void WakeLock::DidReceivePermissionResponse(WakeLockType type,
ScriptPromiseResolver* resolver,
PermissionStatus status) {
- // https://w3c.github.io/wake-lock/#the-request-method
+ // https://w3c.github.io/screen-wake-lock/#the-request-method
DCHECK(status == PermissionStatus::GRANTED ||
status == PermissionStatus::DENIED);
DCHECK(resolver);
@@ -203,7 +203,7 @@ void WakeLock::DidReceivePermissionResponse(WakeLockType type,
}
void WakeLock::ContextDestroyed() {
- // https://w3c.github.io/wake-lock/#handling-document-loss-of-full-activity
+ // https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-full-activity
// 1. Let document be the responsible document of the current settings object.
// 2. Let screenRecord be the platform wake lock's state record associated
// with document and wake lock type "screen".
@@ -220,7 +220,7 @@ void WakeLock::ContextDestroyed() {
}
void WakeLock::PageVisibilityChanged() {
- // https://w3c.github.io/wake-lock/#handling-document-loss-of-visibility
+ // https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-visibility
// 1. Let document be the Document of the top-level browsing context.
// 2. If document's visibility state is "visible", abort these steps.
if (GetPage() && GetPage()->IsPageVisible())
@@ -238,7 +238,7 @@ void WakeLock::PageVisibilityChanged() {
void WakeLock::ObtainPermission(
WakeLockType type,
base::OnceCallback<void(PermissionStatus)> callback) {
- // https://w3c.github.io/wake-lock/#dfn-obtain-permission
+ // https://w3c.github.io/screen-wake-lock/#dfn-obtain-permission
// Note we actually implement a simplified version of the "obtain permission"
// algorithm that essentially just calls the "request permission to use"
// algorithm from the Permissions spec (i.e. we bypass all the steps covering
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 fde48d74ad0..0a8d27e540c 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
@@ -73,7 +73,7 @@ class MODULES_EXPORT WakeLock final : public ScriptWrappable,
HeapMojoWrapperMode::kWithoutContextObserver>
permission_service_;
- // https://w3c.github.io/wake-lock/#concepts-and-state-record
+ // https://w3c.github.io/screen-wake-lock/#concepts-and-state-record
// Each platform wake lock (one per wake lock type) has an associated state
// record per responsible document [...] internal slots.
Member<WakeLockManager> managers_[kWakeLockTypeCount];
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.idl b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.idl
index 16ac657ec3f..0190b141813 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.idl
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.idl
@@ -7,7 +7,7 @@ enum WakeLockType {
"system"
};
-// https://w3c.github.io/wake-lock/#the-wakelock-interface
+// https://w3c.github.io/screen-wake-lock/#the-wakelock-interface
[
SecureContext,
Exposed(DedicatedWorker SystemWakeLock, Window WakeLock)
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc
index 6e875ce03c1..c8cd404b1dd 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.cc
@@ -24,7 +24,7 @@ WakeLockManager::WakeLockManager(ExecutionContext* execution_context,
}
void WakeLockManager::AcquireWakeLock(ScriptPromiseResolver* resolver) {
- // https://w3c.github.io/wake-lock/#acquire-wake-lock-algorithm
+ // https://w3c.github.io/screen-wake-lock/#acquire-wake-lock-algorithm
// 1. If the wake lock for type type is not applicable, return false.
// 2. Set active to true if the platform wake lock has an active wake lock for
// type.
@@ -52,7 +52,7 @@ void WakeLockManager::AcquireWakeLock(ScriptPromiseResolver* resolver) {
&WakeLockManager::OnWakeLockConnectionError, WrapWeakPersistent(this)));
wake_lock_->RequestWakeLock();
}
- // https://w3c.github.io/wake-lock/#the-request-method
+ // https://w3c.github.io/screen-wake-lock/#the-request-method
// 5.2. Let lock be a new WakeLockSentinel object with its type attribute set
// to type.
// 5.4. Resolve promise with lock.
@@ -63,7 +63,7 @@ void WakeLockManager::AcquireWakeLock(ScriptPromiseResolver* resolver) {
}
void WakeLockManager::UnregisterSentinel(WakeLockSentinel* sentinel) {
- // https://w3c.github.io/wake-lock/#release-wake-lock-algorithm
+ // https://w3c.github.io/screen-wake-lock/#release-wake-lock-algorithm
// 1. Let document be the responsible document of the current settings object.
// 2. Let record be the platform wake lock's state record associated with
// document and type.
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h
index dd7ecce3dc3..ad23acd6fe3 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_manager.h
@@ -19,7 +19,7 @@ class ExecutionContext;
class ScriptPromiseResolver;
class WakeLockSentinel;
-// https://w3c.github.io/wake-lock/#concepts-and-state-record
+// https://w3c.github.io/screen-wake-lock/#concepts-and-state-record
// Per-document and per-wake lock type internal data.
class MODULES_EXPORT WakeLockManager final
: public GarbageCollected<WakeLockManager> {
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc
index 182b2648631..3c24465d9a7 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.cc
@@ -23,7 +23,7 @@ WakeLockSentinel::WakeLockSentinel(ScriptState* script_state,
WakeLockSentinel::~WakeLockSentinel() = default;
ScriptPromise WakeLockSentinel::release(ScriptState* script_state) {
- // https://w3c.github.io/wake-lock/#the-release-method
+ // https://w3c.github.io/screen-wake-lock/#the-release-method
// 1. Let promise be a new promise.
// 2. Run the following steps in parallel:
// 2.1. Run release wake lock with lock set to this object and type set to the
@@ -34,8 +34,12 @@ ScriptPromise WakeLockSentinel::release(ScriptState* script_state) {
return ScriptPromise::CastUndefined(script_state);
}
+bool WakeLockSentinel::released() const {
+ return released_;
+}
+
String WakeLockSentinel::type() const {
- // https://w3c.github.io/wake-lock/#dom-wakelocksentinel-type
+ // https://w3c.github.io/screen-wake-lock/#dom-wakelocksentinel-type
// The type attribute corresponds to the WakeLockSentinel's wake lock type.
switch (type_) {
case WakeLockType::kScreen:
@@ -74,7 +78,7 @@ void WakeLockSentinel::ContextDestroyed() {
}
void WakeLockSentinel::DoRelease() {
- // https://w3c.github.io/wake-lock/#release-wake-lock-algorithm
+ // https://w3c.github.io/screen-wake-lock/#release-wake-lock-algorithm
// 1. Let document be the responsible document of the current settings object.
// 2. Let record be the platform wake lock's state record associated with
// document and type.
@@ -90,7 +94,19 @@ void WakeLockSentinel::DoRelease() {
if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed())
return;
- // 6. Queue a task to fire an event named "release" at lock.
+ // 6. Queue a task to run the following steps:
+ GetExecutionContext()
+ ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+ ->PostTask(FROM_HERE, WTF::Bind(&WakeLockSentinel::DispatchReleaseEvent,
+ WrapWeakPersistent(this)));
+}
+
+void WakeLockSentinel::DispatchReleaseEvent() {
+ // https://w3c.github.io/screen-wake-lock/#release-wake-lock-algorithm
+ // 6.1. Set lock.released to true.
+ DCHECK(!released_);
+ released_ = true;
+ // 6.2. Fire an event named "release" at lock.
DispatchEvent(*Event::Create(event_type_names::kRelease));
}
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h
index 7d24cf4ccd8..3d406bf97b7 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.h
@@ -36,6 +36,7 @@ class MODULES_EXPORT WakeLockSentinel final
// Web-exposed interfaces
DEFINE_ATTRIBUTE_EVENT_LISTENER(release, kRelease)
ScriptPromise release(ScriptState*);
+ bool released() const;
String type() const;
// EventTarget overrides.
@@ -60,7 +61,10 @@ class MODULES_EXPORT WakeLockSentinel final
// where |script_state_|'s context is no longer valid.
void DoRelease();
+ void DispatchReleaseEvent();
+
Member<WakeLockManager> manager_;
+ bool released_ = false;
const WakeLockType type_;
FRIEND_TEST_ALL_PREFIXES(WakeLockSentinelTest, MultipleReleaseCalls);
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.idl b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.idl
index c09c08c5878..752c220fb70 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.idl
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel.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://w3c.github.io/wake-lock/#the-wakelocksentinel-interface
+// https://w3c.github.io/screen-wake-lock/#the-wakelocksentinel-interface
[
ActiveScriptWrappable,
@@ -11,6 +11,7 @@
] interface WakeLockSentinel : EventTarget {
attribute EventHandler onrelease;
+ readonly attribute boolean released;
readonly attribute WakeLockType type;
[CallWith=ScriptState] Promise<void> release();
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
index b296e3a4731..daf4cc2e165 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
@@ -51,6 +51,23 @@ TEST(WakeLockSentinelTest, SentinelType) {
EXPECT_EQ("system", sentinel->type());
}
+TEST(WakeLockSentinelTest, SentinelReleased) {
+ MockWakeLockService wake_lock_service;
+ WakeLockTestingContext context(&wake_lock_service);
+
+ auto* manager = MakeGarbageCollected<WakeLockManager>(context.DomWindow(),
+ WakeLockType::kScreen);
+ auto* sentinel = MakeGarbageCollected<WakeLockSentinel>(
+ context.GetScriptState(), WakeLockType::kScreen, manager);
+ EXPECT_FALSE(sentinel->released());
+
+ manager = MakeGarbageCollected<WakeLockManager>(context.DomWindow(),
+ WakeLockType::kSystem);
+ sentinel = MakeGarbageCollected<WakeLockSentinel>(
+ context.GetScriptState(), WakeLockType::kSystem, manager);
+ EXPECT_FALSE(sentinel->released());
+}
+
TEST(WakeLockSentinelTest, MultipleReleaseCalls) {
MockWakeLockService wake_lock_service;
WakeLockTestingContext context(&wake_lock_service);
@@ -65,6 +82,7 @@ TEST(WakeLockSentinelTest, MultipleReleaseCalls) {
auto* sentinel =
ScriptPromiseUtils::GetPromiseResolutionAsWakeLockSentinel(promise);
ASSERT_NE(nullptr, sentinel);
+ EXPECT_FALSE(sentinel->released());
base::RunLoop run_loop;
auto* event_listener =
@@ -75,12 +93,14 @@ TEST(WakeLockSentinelTest, MultipleReleaseCalls) {
sentinel->removeEventListener(event_type_names::kRelease, event_listener);
EXPECT_EQ(nullptr, sentinel->manager_);
+ EXPECT_TRUE(sentinel->released());
event_listener = MakeGarbageCollected<SyncEventListener>(WTF::Bind([]() {
EXPECT_TRUE(false) << "This event handler should not be reached.";
}));
sentinel->addEventListener(event_type_names::kRelease, event_listener);
sentinel->release(context.GetScriptState());
+ EXPECT_TRUE(sentinel->released());
}
TEST(WakeLockSentinelTest, ContextDestruction) {
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
index 4a326dbb99a..29706f07f6b 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
@@ -77,7 +77,7 @@ TEST(WakeLockTest, RequestWakeLockDenied) {
EXPECT_EQ("NotAllowedError", dom_exception->name());
}
-// https://w3c.github.io/wake-lock/#handling-document-loss-of-full-activity
+// https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-full-activity
TEST(WakeLockTest, LossOfDocumentActivity) {
MockWakeLockService wake_lock_service;
WakeLockTestingContext context(&wake_lock_service);
@@ -121,7 +121,7 @@ TEST(WakeLockTest, LossOfDocumentActivity) {
EXPECT_FALSE(system_lock.is_acquired());
}
-// https://w3c.github.io/wake-lock/#handling-document-loss-of-visibility
+// https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-visibility
TEST(WakeLockTest, PageVisibilityHidden) {
MockWakeLockService wake_lock_service;
WakeLockTestingContext context(&wake_lock_service);
@@ -172,7 +172,7 @@ TEST(WakeLockTest, PageVisibilityHidden) {
EXPECT_TRUE(screen_lock.is_acquired());
}
-// https://w3c.github.io/wake-lock/#handling-document-loss-of-visibility
+// https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-visibility
TEST(WakeLockTest, PageVisibilityHiddenBeforeLockAcquisition) {
MockWakeLockService wake_lock_service;
WakeLockTestingContext context(&wake_lock_service);
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
index b03423076eb..1052269f376 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
@@ -100,6 +100,12 @@ void MockWakeLock::WaitForRequest() {
void MockWakeLock::WaitForCancelation() {
DCHECK(!cancel_wake_lock_callback_);
+ if (!receiver_.is_bound()) {
+ // If OnConnectionError() has been called, bail out early to avoid waiting
+ // forever.
+ DCHECK(!is_acquired_);
+ return;
+ }
base::RunLoop run_loop;
cancel_wake_lock_callback_ = run_loop.QuitClosure();
RunWithStack(&run_loop);
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_type.h b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_type.h
index 21d2e65dcf5..c2f018e0331 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_type.h
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock_type.h
@@ -22,7 +22,7 @@ namespace blink {
// WakeLockType enum as a C++ enum, and for converting between WakeLockType and
// device.mojom.WakeLockType.
-// https://w3c.github.io/wake-lock/#the-wakelocktype-enum
+// https://w3c.github.io/screen-wake-lock/#the-wakelocktype-enum
enum class WakeLockType : int8_t { kScreen, kSystem, kMaxValue = kSystem };
// Useful for creating arrays with size N, where N is the number of different
diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl b/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl
index 6523341c170..764e8817110 100644
--- a/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl
+++ b/chromium/third_party/blink/renderer/modules/wake_lock/worker_navigator_wake_lock.idl
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This was originally in
// https://w3c.github.io/wake-lock/#extensions-to-the-workernavigator-interface
+// until System Wake Lock API was split from the Screen Wake Lock API.
[
ImplementedAs=WorkerNavigatorWakeLock,
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
index 54c2e949051..899b871673f 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webaudio/BUILD.gn
@@ -61,8 +61,6 @@ blink_modules_sources("webaudio") {
"audio_worklet_processor_definition.cc",
"audio_worklet_processor_definition.h",
"audio_worklet_processor_error_state.h",
- "audio_worklet_thread.cc",
- "audio_worklet_thread.h",
"base_audio_context.cc",
"base_audio_context.h",
"biquad_dsp_kernel.cc",
@@ -114,6 +112,8 @@ blink_modules_sources("webaudio") {
"offline_audio_context.h",
"offline_audio_destination_node.cc",
"offline_audio_destination_node.h",
+ "offline_audio_worklet_thread.cc",
+ "offline_audio_worklet_thread.h",
"oscillator_node.cc",
"oscillator_node.h",
"panner_node.cc",
@@ -124,8 +124,12 @@ blink_modules_sources("webaudio") {
"realtime_analyser.h",
"realtime_audio_destination_node.cc",
"realtime_audio_destination_node.h",
+ "realtime_audio_worklet_thread.cc",
+ "realtime_audio_worklet_thread.h",
"script_processor_node.cc",
"script_processor_node.h",
+ "semi_realtime_audio_worklet_thread.cc",
+ "semi_realtime_audio_worklet_thread.h",
"stereo_panner_node.cc",
"stereo_panner_node.h",
"wave_shaper_dsp_kernel.cc",
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 960b3fa5b7e..be2d93fdae6 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
@@ -21,7 +21,6 @@
#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/empty_clients.h"
-#include "third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h"
#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -33,22 +32,6 @@ namespace {
const char* const kAutoplayMetric = "WebAudio.Autoplay";
const char* const kAutoplayCrossOriginMetric = "WebAudio.Autoplay.CrossOrigin";
-class MockCrossOriginLocalFrameClient final : public EmptyLocalFrameClient {
- public:
- explicit MockCrossOriginLocalFrameClient(Frame* parent) : parent_(parent) {}
-
- void Trace(Visitor* visitor) const override {
- visitor->Trace(parent_);
- EmptyLocalFrameClient::Trace(visitor);
- }
-
- Frame* Parent() const override { return parent_.Get(); }
- Frame* Top() const override { return parent_.Get(); }
-
- private:
- Member<Frame> parent_;
-};
-
class MockWebAudioDeviceForAutoplayTest : public WebAudioDevice {
public:
explicit MockWebAudioDeviceForAutoplayTest(double sample_rate,
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 195f06e1b18..d37ab20c04d 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
@@ -8,6 +8,7 @@
#include "base/synchronization/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.h"
@@ -18,7 +19,6 @@
#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/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -35,7 +35,7 @@
#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h"
-#include "third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h"
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
@@ -52,18 +52,19 @@ static const size_t kRenderQuantumFrames = 128;
} // namespace
+// The test uses OfflineAudioWorkletThread because the test does not have a
+// strict real-time constraint.
class AudioWorkletGlobalScopeTest : public PageTestBase {
public:
void SetUp() override {
- AudioWorkletThread::EnsureSharedBackingThread();
PageTestBase::SetUp(IntSize());
NavigateTo(KURL("https://example.com/"));
reporting_proxy_ = std::make_unique<WorkerReportingProxy>();
}
- std::unique_ptr<AudioWorkletThread> CreateAudioWorkletThread() {
- std::unique_ptr<AudioWorkletThread> thread =
- AudioWorkletThread::Create(*reporting_proxy_);
+ std::unique_ptr<OfflineAudioWorkletThread> CreateAudioWorkletThread() {
+ std::unique_ptr<OfflineAudioWorkletThread> thread =
+ std::make_unique<OfflineAudioWorkletThread>(*reporting_proxy_);
LocalDOMWindow* window = GetFrame().DomWindow();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
@@ -76,7 +77,7 @@ class AudioWorkletGlobalScopeTest : public PageTestBase {
nullptr /* worker_clients */, nullptr /* content_settings_client */,
window->AddressSpace(), OriginTrialContext::GetTokens(window).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault,
+ mojom::blink::V8CacheOptions::kDefault,
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
@@ -147,9 +148,10 @@ class AudioWorkletGlobalScopeTest : public PageTestBase {
ModuleRecord::Instantiate(script_state, module, js_url);
EXPECT_TRUE(exception.IsEmpty());
- ModuleEvaluationResult result =
+ ScriptEvaluationResult result =
ModuleRecord::Evaluate(script_state, module, js_url);
- return result.IsSuccess();
+ return result.GetResultType() ==
+ ScriptEvaluationResult::ResultType::kSuccess;
}
// Test if AudioWorkletGlobalScope and V8 components (ScriptState, Isolate)
@@ -373,28 +375,32 @@ class AudioWorkletGlobalScopeTest : public PageTestBase {
};
TEST_F(AudioWorkletGlobalScopeTest, Basic) {
- std::unique_ptr<AudioWorkletThread> thread = CreateAudioWorkletThread();
+ std::unique_ptr<OfflineAudioWorkletThread> thread
+ = CreateAudioWorkletThread();
RunBasicTest(thread.get());
thread->Terminate();
thread->WaitForShutdownForTesting();
}
TEST_F(AudioWorkletGlobalScopeTest, Parsing) {
- std::unique_ptr<AudioWorkletThread> thread = CreateAudioWorkletThread();
+ std::unique_ptr<OfflineAudioWorkletThread> thread
+ = CreateAudioWorkletThread();
RunParsingTest(thread.get());
thread->Terminate();
thread->WaitForShutdownForTesting();
}
TEST_F(AudioWorkletGlobalScopeTest, BufferProcessing) {
- std::unique_ptr<AudioWorkletThread> thread = CreateAudioWorkletThread();
+ std::unique_ptr<OfflineAudioWorkletThread> thread
+ = CreateAudioWorkletThread();
RunSimpleProcessTest(thread.get());
thread->Terminate();
thread->WaitForShutdownForTesting();
}
TEST_F(AudioWorkletGlobalScopeTest, ParsingParameterDescriptor) {
- std::unique_ptr<AudioWorkletThread> thread = CreateAudioWorkletThread();
+ std::unique_ptr<OfflineAudioWorkletThread> thread
+ = CreateAudioWorkletThread();
RunParsingParameterDescriptorTest(thread.get());
thread->Terminate();
thread->WaitForShutdownForTesting();
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.cc
index 13df2e3b092..bafdad33d39 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.cc
@@ -6,15 +6,19 @@
#include <utility>
-#include "third_party/blink/public/platform/task_type.h"
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_node.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.h"
#include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h"
-#include "third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h"
#include "third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h"
namespace blink {
@@ -92,7 +96,33 @@ AudioWorkletMessagingProxy::CreateObjectProxy(
}
std::unique_ptr<WorkerThread> AudioWorkletMessagingProxy::CreateWorkerThread() {
- return AudioWorkletThread::Create(WorkletObjectProxy());
+ const auto* frame = To<LocalDOMWindow>(GetExecutionContext())->GetFrame();
+ DCHECK(frame);
+
+ return CreateWorkletThreadWithConstraints(
+ WorkletObjectProxy(),
+ worklet_->GetBaseAudioContext()->HasRealtimeConstraint(),
+ frame->IsMainFrame());
+}
+
+std::unique_ptr<WorkerThread>
+AudioWorkletMessagingProxy::CreateWorkletThreadWithConstraints(
+ WorkerReportingProxy& worker_reporting_proxy,
+ const bool has_realtime_constraint,
+ const bool is_top_level_frame) {
+ if (!has_realtime_constraint)
+ return std::make_unique<OfflineAudioWorkletThread>(worker_reporting_proxy);
+
+ // If the flag is set, it overrides the default thread priority for
+ // subframes. This is only allowed for the experimental purposes, and this
+ // flag will be deprecated in M90.
+ if (is_top_level_frame ||
+ base::FeatureList::IsEnabled(features::kAudioWorkletRealtimeThread)) {
+ return std::make_unique<RealtimeAudioWorkletThread>(worker_reporting_proxy);
+ }
+
+ return std::make_unique<SemiRealtimeAudioWorkletThread>(
+ worker_reporting_proxy);
}
void AudioWorkletMessagingProxy::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h
index 006ec56b231..c5bcc2311a5 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h
@@ -6,7 +6,9 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_WORKLET_MESSAGING_PROXY_H_
#include <memory>
+
#include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
@@ -22,7 +24,8 @@ class WorkerThread;
// AudioWorkletMessagingProxy is a main thread interface for
// AudioWorkletGlobalScope. The proxy communicates with the associated global
// scope via AudioWorkletObjectProxy.
-class AudioWorkletMessagingProxy final : public ThreadedWorkletMessagingProxy {
+class MODULES_EXPORT AudioWorkletMessagingProxy final
+ : public ThreadedWorkletMessagingProxy {
public:
AudioWorkletMessagingProxy(ExecutionContext*, AudioWorklet*);
@@ -59,6 +62,15 @@ class AudioWorkletMessagingProxy final : public ThreadedWorkletMessagingProxy {
// Returns a WorkerThread object backs the AudioWorkletThread instance.
WorkerThread* GetBackingWorkerThread();
+ // Create a Worklet backing thread based on constraints:
+ // 1. AudioContext && top-level frame (or RT thread flag): RT priority thread
+ // 2. AudioContext && sub frame: DISPLAY priority thread
+ // 3. OfflineAudioContext: BACKGROUND priority thread
+ static std::unique_ptr<WorkerThread> CreateWorkletThreadWithConstraints(
+ WorkerReportingProxy&,
+ const bool has_realtime_constraint,
+ const bool is_top_level_frame);
+
void Trace(Visitor*) const override;
private:
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc
index a9b9f5cbb6d..23dcfa97a1d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_object_proxy.cc
@@ -60,8 +60,8 @@ void AudioWorkletObjectProxy::WillDestroyWorkerGlobalScope() {
CrossThreadWeakPersistent<AudioWorkletMessagingProxy>
AudioWorkletObjectProxy::GetAudioWorkletMessagingProxyWeakPtr() {
- return WrapCrossThreadWeakPersistent(
- static_cast<AudioWorkletMessagingProxy*>(MessagingProxyWeakPtr().Get()));
+ return CrossThreadWeakPersistent<AudioWorkletMessagingProxy>(
+ MessagingProxyWeakPtr());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc
deleted file mode 100644
index 116b3d65df5..00000000000
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc
+++ /dev/null
@@ -1,84 +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/webaudio/audio_worklet_thread.h"
-
-#include <memory>
-
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
-#include "third_party/blink/renderer/core/workers/worker_backing_thread.h"
-#include "third_party/blink/renderer/modules/webaudio/audio_worklet.h"
-#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
-#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/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-template class WorkletThreadHolder<AudioWorkletThread>;
-
-unsigned AudioWorkletThread::s_ref_count_ = 0;
-
-std::unique_ptr<AudioWorkletThread> AudioWorkletThread::Create(
- WorkerReportingProxy& worker_reporting_proxy) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
- "AudioWorkletThread::create");
- return base::WrapUnique(new AudioWorkletThread(worker_reporting_proxy));
-}
-
-AudioWorkletThread::AudioWorkletThread(
- WorkerReportingProxy& worker_reporting_proxy)
- : WorkerThread(worker_reporting_proxy) {
- DCHECK(IsMainThread());
- if (++s_ref_count_ == 1) {
- EnsureSharedBackingThread();
- }
-}
-
-AudioWorkletThread::~AudioWorkletThread() {
- DCHECK(IsMainThread());
- if (--s_ref_count_ == 0) {
- ClearSharedBackingThread();
- }
-}
-
-WorkerBackingThread& AudioWorkletThread::GetWorkerBackingThread() {
- return *WorkletThreadHolder<AudioWorkletThread>::GetInstance()->GetThread();
-}
-
-void AudioWorkletThread::EnsureSharedBackingThread() {
- DCHECK(IsMainThread());
-
- ThreadCreationParams params =
- ThreadCreationParams(ThreadType::kAudioWorkletThread);
-
- // TODO(crbug.com/1022888): The worklet thread priority is always NORMAL on
- // linux.
- params.thread_priority =
- base::FeatureList::IsEnabled(features::kAudioWorkletRealtimeThread)
- ? base::ThreadPriority::REALTIME_AUDIO
- : base::ThreadPriority::DISPLAY;
- WorkletThreadHolder<AudioWorkletThread>::EnsureInstance(params);
-}
-
-void AudioWorkletThread::ClearSharedBackingThread() {
- DCHECK(IsMainThread());
- DCHECK_EQ(s_ref_count_, 0u);
- WorkletThreadHolder<AudioWorkletThread>::ClearInstance();
-}
-
-WorkerOrWorkletGlobalScope* AudioWorkletThread::CreateWorkerGlobalScope(
- std::unique_ptr<GlobalScopeCreationParams> creation_params) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
- "AudioWorkletThread::createWorkerGlobalScope");
- return MakeGarbageCollected<AudioWorkletGlobalScope>(
- std::move(creation_params), this);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h
deleted file mode 100644
index d88304ee96e..00000000000
--- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h
+++ /dev/null
@@ -1,53 +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_WEBAUDIO_AUDIO_WORKLET_THREAD_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_WORKLET_THREAD_H_
-
-#include <memory>
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-
-namespace blink {
-
-class WorkerReportingProxy;
-
-// AudioWorkletThread is a per-frame singleton object that has a reference count
-// to the backing thread for the processing of AudioWorkletNode and
-// AudioWorkletProcessor.
-
-class MODULES_EXPORT AudioWorkletThread final : public WorkerThread {
- public:
- static std::unique_ptr<AudioWorkletThread> Create(WorkerReportingProxy&);
- ~AudioWorkletThread() override;
-
- WorkerBackingThread& GetWorkerBackingThread() override;
-
- // The backing thread is cleared by clearSharedBackingThread().
- void ClearWorkerBackingThread() override {}
-
- static void EnsureSharedBackingThread();
- static void ClearSharedBackingThread();
-
- private:
- explicit AudioWorkletThread(WorkerReportingProxy&);
-
- WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
- std::unique_ptr<GlobalScopeCreationParams>) final;
-
- bool IsOwningBackingThread() const override { return false; }
-
- ThreadType GetThreadType() const override {
- return ThreadType::kAudioWorkletThread;
- }
-
- // This is only accessed by the main thread. Incremented by the constructor,
- // and decremented by destructor.
- static unsigned s_ref_count_;
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_WORKLET_THREAD_H_
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 1ec723be819..0a1daa3a000 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
@@ -2,21 +2,26 @@
// 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_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/audio_worklet_messaging_proxy.h"
+#include "third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h"
+#include "third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h"
#include <memory>
+#include <tuple>
+
#include "base/feature_list.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/core/v8/module_record.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/v8_cache_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -49,12 +54,37 @@ class AudioWorkletThreadTest : public PageTestBase {
}
void TearDown() override {
- AudioWorkletThread::ClearSharedBackingThread();
+ OfflineAudioWorkletThread::ClearSharedBackingThread();
+ RealtimeAudioWorkletThread::ClearSharedBackingThread();
+ SemiRealtimeAudioWorkletThread::ClearSharedBackingThread();
+ }
+
+ std::unique_ptr<WorkerThread> CreateAudioWorkletThread(
+ bool has_realtime_constraint, bool is_top_level_frame) {
+ std::unique_ptr<WorkerThread> thread =
+ AudioWorkletMessagingProxy::CreateWorkletThreadWithConstraints(
+ *reporting_proxy_,
+ has_realtime_constraint,
+ is_top_level_frame);
+ StartBackingThread(thread.get());
+ return thread;
+ }
+
+ // Attempts to run some simple script for |thread|.
+ void CheckWorkletCanExecuteScript(WorkerThread* thread) {
+ base::WaitableEvent wait_event;
+ PostCrossThreadTask(
+ *thread->GetWorkerBackingThread().BackingThread().GetTaskRunner(),
+ FROM_HERE,
+ CrossThreadBindOnce(&AudioWorkletThreadTest::ExecuteScriptInWorklet,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(thread),
+ CrossThreadUnretained(&wait_event)));
+ wait_event.Wait();
}
- std::unique_ptr<AudioWorkletThread> CreateAudioWorkletThread() {
- std::unique_ptr<AudioWorkletThread> thread =
- AudioWorkletThread::Create(*reporting_proxy_);
+ private:
+ void StartBackingThread(WorkerThread* thread) {
LocalDOMWindow* window = GetFrame().DomWindow();
thread->Start(
std::make_unique<GlobalScopeCreationParams>(
@@ -67,43 +97,14 @@ class AudioWorkletThreadTest : public PageTestBase {
nullptr /* worker_clients */, nullptr /* content_settings_client */,
window->AddressSpace(), OriginTrialContext::GetTokens(window).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault,
+ mojom::blink::V8CacheOptions::kDefault,
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
window->GetAgentClusterID(), window->GetExecutionContextToken()),
base::nullopt, std::make_unique<WorkerDevToolsParams>());
- return thread;
}
- // Attempts to run some simple script for |thread|.
- void CheckWorkletCanExecuteScript(WorkerThread* thread) {
- base::WaitableEvent wait_event;
- PostCrossThreadTask(
- *thread->GetWorkerBackingThread().BackingThread().GetTaskRunner(),
- FROM_HERE,
- CrossThreadBindOnce(&AudioWorkletThreadTest::ExecuteScriptInWorklet,
- CrossThreadUnretained(this),
- CrossThreadUnretained(thread),
- CrossThreadUnretained(&wait_event)));
- wait_event.Wait();
- }
-
- void CheckWorkletThreadPriority(WorkerThread* thread,
- base::ThreadPriority expected_priority) {
- base::WaitableEvent wait_event;
- PostCrossThreadTask(
- *thread->GetWorkerBackingThread().BackingThread().GetTaskRunner(),
- FROM_HERE,
- CrossThreadBindOnce(&AudioWorkletThreadTest::CheckThreadPriority,
- CrossThreadUnretained(this),
- CrossThreadUnretained(thread),
- expected_priority,
- CrossThreadUnretained(&wait_event)));
- wait_event.Wait();
- }
-
- private:
void ExecuteScriptInWorklet(WorkerThread* thread,
base::WaitableEvent* wait_event) {
ScriptState* script_state =
@@ -119,25 +120,10 @@ class AudioWorkletThreadTest : public PageTestBase {
ScriptValue exception =
ModuleRecord::Instantiate(script_state, module, js_url);
EXPECT_TRUE(exception.IsEmpty());
- ModuleEvaluationResult result =
+ ScriptEvaluationResult result =
ModuleRecord::Evaluate(script_state, module, js_url);
- EXPECT_TRUE(result.IsSuccess());
- wait_event->Signal();
- }
-
- void CheckThreadPriority(WorkerThread* thread,
- base::ThreadPriority expected_priority,
- base::WaitableEvent* wait_event) {
- ASSERT_TRUE(thread->IsCurrentThread());
-// TODO(crbug.com/1022888): The worklet thread priority is always NORMAL on
-// linux.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
- base::ThreadPriority::NORMAL);
-#else
- EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
- expected_priority);
-#endif
+ EXPECT_EQ(result.GetResultType(),
+ ScriptEvaluationResult::ResultType::kSuccess);
wait_event->Signal();
}
@@ -145,131 +131,280 @@ class AudioWorkletThreadTest : public PageTestBase {
};
TEST_F(AudioWorkletThreadTest, Basic) {
- std::unique_ptr<AudioWorkletThread> worklet = CreateAudioWorkletThread();
- CheckWorkletCanExecuteScript(worklet.get());
- worklet->Terminate();
- worklet->WaitForShutdownForTesting();
+ std::unique_ptr<WorkerThread> audio_worklet_thread =
+ CreateAudioWorkletThread(true, true);
+ CheckWorkletCanExecuteScript(audio_worklet_thread.get());
+ audio_worklet_thread->Terminate();
+ audio_worklet_thread->WaitForShutdownForTesting();
}
-// Tests that the same WebThread is used for new worklets if the WebThread is
-// still alive.
-TEST_F(AudioWorkletThreadTest, CreateSecondAndTerminateFirst) {
- // Create the first worklet and wait until it is initialized.
- std::unique_ptr<AudioWorkletThread> first_worklet =
- CreateAudioWorkletThread();
- Thread* first_thread =
- &first_worklet->GetWorkerBackingThread().BackingThread();
- CheckWorkletCanExecuteScript(first_worklet.get());
- v8::Isolate* first_isolate = first_worklet->GetIsolate();
- ASSERT_TRUE(first_isolate);
-
- // Create the second worklet and immediately destroy the first worklet.
- std::unique_ptr<AudioWorkletThread> second_worklet =
- CreateAudioWorkletThread();
- // We don't use terminateAndWait here to avoid forcible termination.
- first_worklet->Terminate();
- first_worklet->WaitForShutdownForTesting();
+// Creates 2 different AudioWorkletThreads with different RT constraints.
+// Checks if they are running on a different thread.
+TEST_F(AudioWorkletThreadTest, CreateDifferentWorkletThreadsAndTerminate_1) {
+ // Create RealtimeAudioWorkletThread.
+ std::unique_ptr<WorkerThread> first_worklet_thread =
+ CreateAudioWorkletThread(true, true);
+ Thread* first_backing_thread =
+ &first_worklet_thread->GetWorkerBackingThread().BackingThread();
+ v8::Isolate* first_isolate = first_worklet_thread->GetIsolate();
+
+ // Create OfflineAudioWorkletThread.
+ std::unique_ptr<WorkerThread> second_worklet_thread =
+ CreateAudioWorkletThread(false, true);
+ Thread* second_backing_thread =
+ &second_worklet_thread->GetWorkerBackingThread().BackingThread();
+ v8::Isolate* second_isolate = second_worklet_thread->GetIsolate();
+
+ // Check if they are two different threads, and two different v8::isolates.
+ ASSERT_NE(first_backing_thread, second_backing_thread);
+ ASSERT_NE(first_isolate, second_isolate);
+
+ first_worklet_thread->Terminate();
+ first_worklet_thread->WaitForShutdownForTesting();
+ second_worklet_thread->Terminate();
+ second_worklet_thread->WaitForShutdownForTesting();
+}
- // Wait until the second worklet is initialized. Verify that the second
- // worklet is using the same thread and Isolate as the first worklet.
- Thread* second_thread =
- &second_worklet->GetWorkerBackingThread().BackingThread();
- ASSERT_EQ(first_thread, second_thread);
+// Creates 2 AudioWorkletThreads with RT constraint from 2 different
+// originating frames. Checks if they are running on a different thread.
+TEST_F(AudioWorkletThreadTest, CreateDifferentWorkletThreadsAndTerminate_2) {
+ // Create an AudioWorkletThread from a main frame with RT constraint.
+ std::unique_ptr<WorkerThread> first_worklet_thread =
+ CreateAudioWorkletThread(true, true);
+ Thread* first_backing_thread =
+ &first_worklet_thread->GetWorkerBackingThread().BackingThread();
+ v8::Isolate* first_isolate = first_worklet_thread->GetIsolate();
+
+ // Create an AudioWorkletThread from a sub frame with RT constraint.
+ std::unique_ptr<WorkerThread> second_worklet_thread =
+ CreateAudioWorkletThread(true, false);
+ Thread* second_backing_thread =
+ &second_worklet_thread->GetWorkerBackingThread().BackingThread();
+ v8::Isolate* second_isolate = second_worklet_thread->GetIsolate();
+
+ // Check if they are two different threads, and two different v8::isolates.
+ ASSERT_NE(first_backing_thread, second_backing_thread);
+ ASSERT_NE(first_isolate, second_isolate);
+
+ first_worklet_thread->Terminate();
+ first_worklet_thread->WaitForShutdownForTesting();
+ second_worklet_thread->Terminate();
+ second_worklet_thread->WaitForShutdownForTesting();
+}
- v8::Isolate* second_isolate = second_worklet->GetIsolate();
- ASSERT_TRUE(second_isolate);
- EXPECT_EQ(first_isolate, second_isolate);
+class AudioWorkletThreadInteractionTest
+ : public AudioWorkletThreadTest,
+ public testing::WithParamInterface<std::tuple<bool, bool>> {
+ public:
+ AudioWorkletThreadInteractionTest()
+ : has_realtime_constraint_(std::get<0>(GetParam())),
+ is_top_level_frame_(std::get<1>(GetParam())) {}
- // Verify that the worklet can still successfully execute script.
- CheckWorkletCanExecuteScript(second_worklet.get());
+ protected:
+ const bool has_realtime_constraint_;
+ const bool is_top_level_frame_;
+};
- second_worklet->Terminate();
- second_worklet->WaitForShutdownForTesting();
+TEST_P(AudioWorkletThreadInteractionTest, CreateSecondAndTerminateFirst) {
+ // Create the first worklet and wait until it is initialized.
+ std::unique_ptr<WorkerThread> first_worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ Thread* first_backing_thread =
+ &first_worklet_thread->GetWorkerBackingThread().BackingThread();
+ CheckWorkletCanExecuteScript(first_worklet_thread.get());
+ v8::Isolate* first_isolate = first_worklet_thread->GetIsolate();
+ ASSERT_TRUE(first_isolate);
+
+ // Create the second worklet and immediately destroy the first worklet.
+ std::unique_ptr<WorkerThread> second_worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ // We don't use terminateAndWait here to avoid forcible termination.
+ first_worklet_thread->Terminate();
+ first_worklet_thread->WaitForShutdownForTesting();
+
+ // Wait until the second worklet is initialized. Verify that the second
+ // worklet is using the same thread and Isolate as the first worklet.
+ Thread* second_backing_thread =
+ &second_worklet_thread->GetWorkerBackingThread().BackingThread();
+ ASSERT_EQ(first_backing_thread, second_backing_thread);
+
+ v8::Isolate* second_isolate = second_worklet_thread->GetIsolate();
+ ASSERT_TRUE(second_isolate);
+ EXPECT_EQ(first_isolate, second_isolate);
+
+ // Verify that the worklet can still successfully execute script.
+ CheckWorkletCanExecuteScript(second_worklet_thread.get());
+
+ second_worklet_thread->Terminate();
+ second_worklet_thread->WaitForShutdownForTesting();
}
-// Tests that a new WebThread is created if all existing worklets are
-// terminated before a new worklet is created.
-TEST_F(AudioWorkletThreadTest, TerminateFirstAndCreateSecond) {
+TEST_P(AudioWorkletThreadInteractionTest, TerminateFirstAndCreateSecond) {
// Create the first worklet, wait until it is initialized, and terminate it.
- std::unique_ptr<AudioWorkletThread> worklet = CreateAudioWorkletThread();
- Thread* first_thread = &worklet->GetWorkerBackingThread().BackingThread();
- CheckWorkletCanExecuteScript(worklet.get());
+ std::unique_ptr<WorkerThread> worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ Thread* first_backing_thread =
+ &worklet_thread->GetWorkerBackingThread().BackingThread();
+ CheckWorkletCanExecuteScript(worklet_thread.get());
// We don't use terminateAndWait here to avoid forcible termination.
- worklet->Terminate();
- worklet->WaitForShutdownForTesting();
+ worklet_thread->Terminate();
+ worklet_thread->WaitForShutdownForTesting();
// Create the second worklet. The backing thread is same.
- worklet = CreateAudioWorkletThread();
- Thread* second_thread = &worklet->GetWorkerBackingThread().BackingThread();
- EXPECT_EQ(first_thread, second_thread);
- CheckWorkletCanExecuteScript(worklet.get());
-
- worklet->Terminate();
- worklet->WaitForShutdownForTesting();
+ worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ Thread* second_backing_thread =
+ &worklet_thread->GetWorkerBackingThread().BackingThread();
+ EXPECT_EQ(first_backing_thread, second_backing_thread);
+ CheckWorkletCanExecuteScript(worklet_thread.get());
+
+ worklet_thread->Terminate();
+ worklet_thread->WaitForShutdownForTesting();
}
-// Tests that v8::Isolate and WebThread are correctly set-up if a worklet is
-// created while another is terminating.
-TEST_F(AudioWorkletThreadTest, CreatingSecondDuringTerminationOfFirst) {
- std::unique_ptr<AudioWorkletThread> first_worklet =
- CreateAudioWorkletThread();
- CheckWorkletCanExecuteScript(first_worklet.get());
- v8::Isolate* first_isolate = first_worklet->GetIsolate();
+TEST_P(AudioWorkletThreadInteractionTest,
+ CreatingSecondDuringTerminationOfFirst) {
+ // Tests that v8::Isolate and WebThread are correctly set-up if a worklet is
+ // created while another is terminating.
+ std::unique_ptr<WorkerThread> first_worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ CheckWorkletCanExecuteScript(first_worklet_thread.get());
+ v8::Isolate* first_isolate = first_worklet_thread->GetIsolate();
ASSERT_TRUE(first_isolate);
// Request termination of the first worklet and create the second worklet
// as soon as possible. We don't wait for its termination.
// Note: We rely on the assumption that the termination steps don't run
// on the worklet thread so quickly. This could be a source of flakiness.
- first_worklet->Terminate();
- std::unique_ptr<AudioWorkletThread> second_worklet =
- CreateAudioWorkletThread();
+ first_worklet_thread->Terminate();
- v8::Isolate* second_isolate = second_worklet->GetIsolate();
+ std::unique_ptr<WorkerThread> second_worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint_, is_top_level_frame_);
+ v8::Isolate* second_isolate = second_worklet_thread->GetIsolate();
ASSERT_TRUE(second_isolate);
- EXPECT_EQ(first_isolate, second_isolate);
+
+ ASSERT_EQ(first_isolate, second_isolate);
// Verify that the isolate can run some scripts correctly in the second
// worklet.
- CheckWorkletCanExecuteScript(second_worklet.get());
- second_worklet->Terminate();
- second_worklet->WaitForShutdownForTesting();
+ CheckWorkletCanExecuteScript(second_worklet_thread.get());
+ second_worklet_thread->Terminate();
+ second_worklet_thread->WaitForShutdownForTesting();
}
-class AudioWorkletThreadDisplayPriorityTest : public AudioWorkletThreadTest {
- public:
- AudioWorkletThreadDisplayPriorityTest() {
- feature_list_.InitAndDisableFeature(features::kAudioWorkletRealtimeThread);
- }
+INSTANTIATE_TEST_SUITE_P(AudioWorkletThreadInteractionTest,
+ AudioWorkletThreadInteractionTest,
+ testing::Combine(testing::Bool(), testing::Bool()));
- private:
- base::test::ScopedFeatureList feature_list_;
+struct ThreadPriorityTestParam {
+ const bool has_realtime_constraint;
+ const bool is_top_level_frame;
+ const bool is_flag_enabled;
+ const base::ThreadPriority expected_priority;
};
-TEST_F(AudioWorkletThreadDisplayPriorityTest, DisplayPriority) {
- std::unique_ptr<AudioWorkletThread> worklet = CreateAudioWorkletThread();
- CheckWorkletThreadPriority(worklet.get(), base::ThreadPriority::DISPLAY);
- worklet->Terminate();
- worklet->WaitForShutdownForTesting();
-}
+constexpr ThreadPriorityTestParam kThreadPriorityTestParams[] = {
+ // A real-time priority thread is guaranteed when the context has real-time
+ // constraint and is spawned from a top-level frame. The flag setting
+ // is ignored.
+ {true, true, true, base::ThreadPriority::REALTIME_AUDIO},
+ {true, true, false, base::ThreadPriority::REALTIME_AUDIO},
+
+ // A DISPLAY priority thread is given when the context has real-time
+ // constraint but is spawned from a sub frame.
+ {true, false, false, base::ThreadPriority::DISPLAY},
+
+ // Enabling the real-time thread flag will override thread priority logic
+ // for a real-time context.
+ {true, false, true, base::ThreadPriority::REALTIME_AUDIO},
+
+ // OfflineAudioWorkletThread is always a NORMAL priority no matter what
+ // the flag setting or the originating frame level is.
+ {false, true, true, base::ThreadPriority::NORMAL},
+ {false, true, false, base::ThreadPriority::NORMAL},
+ {false, false, true, base::ThreadPriority::NORMAL},
+ {false, false, false, base::ThreadPriority::NORMAL},
+};
-class AudioWorkletThreadRealtimePriorityTest : public AudioWorkletThreadTest {
+class AudioWorkletThreadPriorityTest
+ : public AudioWorkletThreadTest,
+ public testing::WithParamInterface<ThreadPriorityTestParam> {
public:
- AudioWorkletThreadRealtimePriorityTest() {
- feature_list_.InitAndEnableFeature(features::kAudioWorkletRealtimeThread);
+ AudioWorkletThreadPriorityTest() = default;
+
+ void InitAndSetRealtimePriorityFlag(bool is_flag_enabled) {
+ if (is_flag_enabled) {
+ feature_list_.InitAndEnableFeature(features::kAudioWorkletRealtimeThread);
+ } else {
+ feature_list_.InitAndDisableFeature(
+ features::kAudioWorkletRealtimeThread);
+ }
+ }
+
+ void CreateCheckThreadPriority(bool has_realtime_constraint,
+ bool is_top_level_frame,
+ base::ThreadPriority expected_priority) {
+ std::unique_ptr<WorkerThread> audio_worklet_thread =
+ CreateAudioWorkletThread(has_realtime_constraint, is_top_level_frame);
+ WorkerThread* thread = audio_worklet_thread.get();
+ base::WaitableEvent wait_event;
+ PostCrossThreadTask(
+ *thread->GetWorkerBackingThread().BackingThread().GetTaskRunner(),
+ FROM_HERE,
+ CrossThreadBindOnce(
+ &AudioWorkletThreadPriorityTest::CheckThreadPriorityOnWorkerThread,
+ CrossThreadUnretained(this),
+ CrossThreadUnretained(thread),
+ expected_priority,
+ CrossThreadUnretained(&wait_event)));
+ wait_event.Wait();
+ audio_worklet_thread->Terminate();
+ audio_worklet_thread->WaitForShutdownForTesting();
}
private:
+ void CheckThreadPriorityOnWorkerThread(
+ WorkerThread* thread,
+ base::ThreadPriority expected_priority,
+ base::WaitableEvent* wait_event) {
+ ASSERT_TRUE(thread->IsCurrentThread());
+ base::ThreadPriority actual_priority =
+ base::PlatformThread::GetCurrentThreadPriority();
+
+ // TODO(crbug.com/1022888): The worklet thread priority is always NORMAL
+ // on OS_LINUX and OS_CHROMEOS regardless of the thread priority setting.
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+ if (expected_priority == base::ThreadPriority::REALTIME_AUDIO ||
+ expected_priority == base::ThreadPriority::DISPLAY) {
+ EXPECT_EQ(actual_priority, base::ThreadPriority::NORMAL);
+ } else {
+ EXPECT_EQ(actual_priority, expected_priority);
+ }
+#elif defined(OS_FUCHSIA)
+ // The thread priority is no-op on Fuchsia. It's always NORMAL priority.
+ // See crbug.com/1090245.
+ EXPECT_EQ(actual_priority, base::ThreadPriority::NORMAL);
+#else
+ EXPECT_EQ(actual_priority, expected_priority);
+#endif
+
+ wait_event->Signal();
+ }
+
base::test::ScopedFeatureList feature_list_;
};
-TEST_F(AudioWorkletThreadRealtimePriorityTest, RealtimePriority) {
- std::unique_ptr<AudioWorkletThread> worklet = CreateAudioWorkletThread();
- CheckWorkletThreadPriority(worklet.get(),
- base::ThreadPriority::REALTIME_AUDIO);
- worklet->Terminate();
- worklet->WaitForShutdownForTesting();
+TEST_P(AudioWorkletThreadPriorityTest, CheckThreadPriority) {
+ const auto& test_param = GetParam();
+ InitAndSetRealtimePriorityFlag(test_param.is_flag_enabled);
+ CreateCheckThreadPriority(test_param.has_realtime_constraint,
+ test_param.is_top_level_frame,
+ test_param.expected_priority);
}
+INSTANTIATE_TEST_SUITE_P(AudioWorkletThreadPriorityTest,
+ AudioWorkletThreadPriorityTest,
+ testing::ValuesIn(kThreadPriorityTestParams));
+
} // namespace blink
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 e203973a516..db8b7c5cc0d 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
@@ -141,7 +141,6 @@ void BaseAudioContext::Initialize() {
}
void BaseAudioContext::Clear() {
- destination_node_.Clear();
// The audio rendering thread is dead. Nobody will schedule AudioHandler
// deletion. Let's do it ourselves.
GetDeferredTaskHandler().ClearHandlersToBeDeleted();
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
index 13eca1ad65c..ffd2965c015 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
+++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
@@ -24,7 +24,7 @@ callback DecodeSuccessCallback = void (AudioBuffer decodedData);
readonly attribute double currentTime;
// All AudioNodes in the context run at this sample-rate (sample-frames per second).
- readonly attribute float sampleRate;
+ [HighEntropy=Direct, Measure] readonly attribute float sampleRate;
// All panning is relative to this listener.
readonly attribute AudioListener listener;
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 2e16a6b66dc..bf000d17d8b 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc
@@ -152,6 +152,31 @@ void ConvolverHandler::SetBuffer(AudioBuffer* buffer,
// reference to it is kept for later use in that class.
scoped_refptr<AudioBus> buffer_bus =
AudioBus::Create(number_of_channels, buffer_length, false);
+
+ // Check to see if any of the channels have been transferred. Note that an
+ // AudioBuffer cannot be created with a length of 0, so if any channel has a
+ // length of 0, it was transferred.
+ bool any_buffer_detached = false;
+ for (unsigned i = 0; i < number_of_channels; ++i) {
+ for (unsigned i = 0; i < number_of_channels; ++i) {
+ if (buffer->getChannelData(i)->lengthAsSizeT() == 0) {
+ any_buffer_detached = true;
+ break;
+ }
+ }
+ }
+
+ if (any_buffer_detached) {
+ // If any channel is detached, we're supposed to treat it as if all were.
+ // This means the buffer effectively has length 0, which is the same as if
+ // no buffer were given.
+ BaseAudioContext::GraphAutoLocker context_locker(Context());
+ MutexLocker locker(process_lock_);
+ reverb_.reset();
+ shared_buffer_ = nullptr;
+ return;
+ }
+
for (unsigned i = 0; i < number_of_channels; ++i) {
buffer_bus->SetChannelMemory(i, buffer->getChannelData(i).View()->Data(),
buffer_length);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc b/chromium/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc
index e5ecb6655dc..d64d57212a5 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc
@@ -33,7 +33,8 @@ std::tuple<int, double> OscillatorHandler::ProcessKRateVector(
double virtual_read_index,
float frequency,
float rate_scale) const {
- const unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ auto periodic_wave = periodic_wave_.Lock();
+ const unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
const double inv_periodic_wave_size = 1.0 / periodic_wave_size;
float* higher_wave_data = nullptr;
@@ -42,7 +43,7 @@ std::tuple<int, double> OscillatorHandler::ProcessKRateVector(
const float incr = frequency * rate_scale;
DCHECK_GE(incr, kInterpolate2Point);
- periodic_wave_->WaveDataForFundamentalFrequency(
+ periodic_wave->WaveDataForFundamentalFrequency(
frequency, lower_wave_data, higher_wave_data, table_interpolation_factor);
const float32x4_t v_wave_size = vdupq_n_f32(periodic_wave_size);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc b/chromium/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
index 75850eb35fa..17207893d7d 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
@@ -46,7 +46,8 @@ std::tuple<int, double> OscillatorHandler::ProcessKRateVector(
double virtual_read_index,
float frequency,
float rate_scale) const {
- const unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ auto periodic_wave = periodic_wave_.Lock();
+ const unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
const double inv_periodic_wave_size = 1.0 / periodic_wave_size;
float* higher_wave_data = nullptr;
@@ -55,7 +56,7 @@ std::tuple<int, double> OscillatorHandler::ProcessKRateVector(
float incr = frequency * rate_scale;
DCHECK_GE(incr, kInterpolate2Point);
- periodic_wave_->WaveDataForFundamentalFrequency(
+ periodic_wave->WaveDataForFundamentalFrequency(
frequency, lower_wave_data, higher_wave_data, table_interpolation_factor);
const __m128 v_wave_size = _mm_set1_ps(periodic_wave_size);
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc
index a9ca0605ef3..96b646a82d6 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc
@@ -90,8 +90,9 @@ MediaElementAudioSourceHandler::~MediaElementAudioSourceHandler() {
Uninitialize();
}
-HTMLMediaElement* MediaElementAudioSourceHandler::MediaElement() const {
- return media_element_.Get();
+CrossThreadPersistent<HTMLMediaElement>
+MediaElementAudioSourceHandler::MediaElement() const {
+ return media_element_.Lock();
}
void MediaElementAudioSourceHandler::Dispose() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h
index c41b82d7373..950368bcd51 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h
@@ -49,7 +49,7 @@ class MediaElementAudioSourceHandler final : public AudioHandler {
HTMLMediaElement&);
~MediaElementAudioSourceHandler() override;
- HTMLMediaElement* MediaElement() const;
+ CrossThreadPersistent<HTMLMediaElement> MediaElement() const;
// AudioHandler
void Dispose() override;
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
index 5d38b5407bf..828dff2bcac 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/wtf/uuid.h"
@@ -63,7 +64,8 @@ MediaStreamAudioDestinationHandler::MediaStreamAudioDestinationHandler(
source_(static_cast<MediaStreamAudioDestinationNode&>(node).source()),
mix_bus_(AudioBus::Create(number_of_channels,
audio_utilities::kRenderQuantumFrames)) {
- source_->SetAudioFormat(number_of_channels, node.context()->sampleRate());
+ source_.Lock()->SetAudioFormat(number_of_channels,
+ node.context()->sampleRate());
SetInternalChannelCountMode(kExplicit);
Initialize();
}
@@ -89,6 +91,8 @@ void MediaStreamAudioDestinationHandler::Process(uint32_t number_of_frames) {
// Synchronize with possible dynamic changes to the channel count.
MutexTryLocker try_locker(process_lock_);
+ auto source = source_.Lock();
+
// If we can get the lock, we can process normally by updating the
// mix bus to a new channel count, if needed. If not, just use the
// old mix bus to do the mixing; we'll update the bus next time
@@ -99,7 +103,7 @@ void MediaStreamAudioDestinationHandler::Process(uint32_t number_of_frames) {
mix_bus_ = AudioBus::Create(count, audio_utilities::kRenderQuantumFrames);
// setAudioFormat has an internal lock. This can cause audio to
// glitch. This is outside of our control.
- source_->SetAudioFormat(count, Context()->sampleRate());
+ source->SetAudioFormat(count, Context()->sampleRate());
}
}
@@ -107,7 +111,7 @@ void MediaStreamAudioDestinationHandler::Process(uint32_t number_of_frames) {
// consumeAudio has an internal lock (also used by setAudioFormat).
// This can cause audio to glitch. This is outside of our control.
- source_->ConsumeAudio(mix_bus_.get(), number_of_frames);
+ source->ConsumeAudio(mix_bus_.get(), number_of_frames);
}
void MediaStreamAudioDestinationHandler::SetChannelCount(
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.cc
new file mode 100644
index 00000000000..7673535f031
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.cc
@@ -0,0 +1,65 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h"
+
+#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+
+namespace blink {
+
+template class WorkletThreadHolder<OfflineAudioWorkletThread>;
+
+int OfflineAudioWorkletThread::s_ref_count_ = 0;
+
+OfflineAudioWorkletThread::OfflineAudioWorkletThread(
+ WorkerReportingProxy& worker_reporting_proxy)
+ : WorkerThread(worker_reporting_proxy) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "OfflineAudioWorkletThread()");
+
+ DCHECK(IsMainThread());
+
+ ThreadCreationParams params =
+ ThreadCreationParams(ThreadType::kOfflineAudioWorkletThread);
+
+ // OfflineAudioWorkletThread always uses a NORMAL priority thread.
+ params.thread_priority = base::ThreadPriority::NORMAL;
+
+ if (++s_ref_count_ == 1)
+ EnsureSharedBackingThread(params);
+}
+
+OfflineAudioWorkletThread::~OfflineAudioWorkletThread() {
+ DCHECK(IsMainThread());
+ if (--s_ref_count_ == 0)
+ ClearSharedBackingThread();
+}
+
+WorkerBackingThread& OfflineAudioWorkletThread::GetWorkerBackingThread() {
+ return *WorkletThreadHolder<OfflineAudioWorkletThread>::GetInstance()
+ ->GetThread();
+}
+
+void OfflineAudioWorkletThread::EnsureSharedBackingThread(
+ const ThreadCreationParams& params) {
+ DCHECK(IsMainThread());
+ WorkletThreadHolder<OfflineAudioWorkletThread>::EnsureInstance(params);
+}
+
+void OfflineAudioWorkletThread::ClearSharedBackingThread() {
+ DCHECK(IsMainThread());
+ CHECK_EQ(s_ref_count_, 0);
+ WorkletThreadHolder<OfflineAudioWorkletThread>::ClearInstance();
+}
+
+WorkerOrWorkletGlobalScope* OfflineAudioWorkletThread::CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams> creation_params) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "OfflineAudioWorkletThread::CreateWorkerGlobalScope");
+ return MakeGarbageCollected<AudioWorkletGlobalScope>(
+ std::move(creation_params), this);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h
new file mode 100644
index 00000000000..586531e134c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_worklet_thread.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_WORKLET_THREAD_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_WORKLET_THREAD_H_
+
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class WorkerReportingProxy;
+struct ThreadCreationParams;
+
+// OfflineAudioWorkletThread is a per-AudioWorkletGlobalScope object that has a
+// reference count to the backing thread that performs AudioWorklet tasks.
+// Its backing thread uses NORMAL priority no matter what the environment
+// or the feature flag setting is.
+class MODULES_EXPORT OfflineAudioWorkletThread final : public WorkerThread {
+ public:
+ explicit OfflineAudioWorkletThread(WorkerReportingProxy&);
+ ~OfflineAudioWorkletThread() final;
+
+ WorkerBackingThread& GetWorkerBackingThread() final;
+ void ClearWorkerBackingThread() final {}
+
+ static void EnsureSharedBackingThread(const ThreadCreationParams&);
+ static void ClearSharedBackingThread();
+
+ private:
+ WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams>) final;
+ bool IsOwningBackingThread() const final { return false; }
+ ThreadType GetThreadType() const final {
+ return ThreadType::kOfflineAudioWorkletThread;
+ }
+
+ // Use for ref-counting of all OfflineAudioWorkletThread instances in a
+ // process. Incremented by the constructor and decremented by destructor.
+ static int s_ref_count_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_WORKLET_THREAD_H_
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc
index 9d3da29468f..1e47684ba9e 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -197,7 +198,7 @@ bool OscillatorHandler::CalculateSampleAccuratePhaseIncrements(
bool has_frequency_changes = false;
float* phase_increments = phase_increments_.Data();
- float final_scale = periodic_wave_->RateScale();
+ float final_scale = periodic_wave_.Lock()->RateScale();
if (frequency_->HasSampleAccurateValues() && frequency_->IsAudioRate()) {
has_sample_accurate_values = true;
@@ -437,7 +438,8 @@ double OscillatorHandler::ProcessKRateScalar(int start,
double virtual_read_index,
float frequency,
float rate_scale) const {
- const unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ auto periodic_wave = periodic_wave_.Lock();
+ const unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
const double inv_periodic_wave_size = 1.0 / periodic_wave_size;
const unsigned read_index_mask = periodic_wave_size - 1;
@@ -445,7 +447,7 @@ double OscillatorHandler::ProcessKRateScalar(int start,
float* lower_wave_data = nullptr;
float table_interpolation_factor = 0;
- periodic_wave_->WaveDataForFundamentalFrequency(
+ periodic_wave->WaveDataForFundamentalFrequency(
frequency, lower_wave_data, higher_wave_data, table_interpolation_factor);
const float incr = frequency * rate_scale;
@@ -491,7 +493,8 @@ double OscillatorHandler::ProcessKRateScalar(int start,
double OscillatorHandler::ProcessKRate(int n,
float* dest_p,
double virtual_read_index) const {
- const unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ auto periodic_wave = periodic_wave_.Lock();
+ const unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
const double inv_periodic_wave_size = 1.0 / periodic_wave_size;
const unsigned read_index_mask = periodic_wave_size - 1;
@@ -503,10 +506,10 @@ double OscillatorHandler::ProcessKRate(int n,
const float detune_scale = DetuneToFrequencyMultiplier(detune_->FinalValue());
frequency *= detune_scale;
ClampFrequency(&frequency, 1, Context()->sampleRate() / 2);
- periodic_wave_->WaveDataForFundamentalFrequency(
+ periodic_wave->WaveDataForFundamentalFrequency(
frequency, lower_wave_data, higher_wave_data, table_interpolation_factor);
- const float rate_scale = periodic_wave_->RateScale();
+ const float rate_scale = periodic_wave->RateScale();
const float incr = frequency * rate_scale;
if (incr >= kInterpolate2Point) {
@@ -552,9 +555,10 @@ std::tuple<int, double> OscillatorHandler::ProcessARateVector(
float* destination,
double virtual_read_index,
const float* phase_increments) const {
- float rate_scale = periodic_wave_->RateScale();
+ auto periodic_wave = periodic_wave_.Lock();
+ float rate_scale = periodic_wave->RateScale();
float inv_rate_scale = 1 / rate_scale;
- unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
double inv_periodic_wave_size = 1.0 / periodic_wave_size;
unsigned read_index_mask = periodic_wave_size - 1;
@@ -576,9 +580,9 @@ std::tuple<int, double> OscillatorHandler::ProcessARateVector(
frequency[m] = inv_rate_scale * phase_incr;
}
- periodic_wave_->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
- higher_wave_data,
- table_interpolation_factor);
+ periodic_wave->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
+ higher_wave_data,
+ table_interpolation_factor);
// If all the phase increments are large enough, we can use linear
// interpolation with a possibly vectorized implementation. If not, we need
@@ -616,9 +620,10 @@ double OscillatorHandler::ProcessARateScalar(
float* destination,
double virtual_read_index,
const float* phase_increments) const {
- float rate_scale = periodic_wave_->RateScale();
+ auto periodic_wave = periodic_wave_.Lock();
+ float rate_scale = periodic_wave->RateScale();
float inv_rate_scale = 1 / rate_scale;
- unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
double inv_periodic_wave_size = 1.0 / periodic_wave_size;
unsigned read_index_mask = periodic_wave_size - 1;
@@ -630,9 +635,9 @@ double OscillatorHandler::ProcessARateScalar(
float incr = phase_increments[m];
float frequency = inv_rate_scale * incr;
- periodic_wave_->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
- higher_wave_data,
- table_interpolation_factor);
+ periodic_wave->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
+ higher_wave_data,
+ table_interpolation_factor);
float sample = DoInterpolation(virtual_read_index, fabs(incr),
read_index_mask, table_interpolation_factor,
@@ -684,8 +689,10 @@ void OscillatorHandler::Process(uint32_t frames_to_process) {
return;
}
+ auto periodic_wave = periodic_wave_.Lock();
+
// We must access m_periodicWave only inside the lock.
- if (!periodic_wave_.Get()) {
+ if (!periodic_wave.Get()) {
output_bus->Zero();
return;
}
@@ -703,7 +710,7 @@ void OscillatorHandler::Process(uint32_t frames_to_process) {
return;
}
- unsigned periodic_wave_size = periodic_wave_->PeriodicWaveSize();
+ unsigned periodic_wave_size = periodic_wave->PeriodicWaveSize();
float* dest_p = output_bus->Channel(0)->MutableData();
@@ -712,7 +719,7 @@ void OscillatorHandler::Process(uint32_t frames_to_process) {
// We keep virtualReadIndex double-precision since we're accumulating values.
double virtual_read_index = virtual_read_index_;
- float rate_scale = periodic_wave_->RateScale();
+ float rate_scale = periodic_wave->RateScale();
bool has_sample_accurate_values =
CalculateSampleAccuratePhaseIncrements(frames_to_process);
@@ -727,9 +734,9 @@ void OscillatorHandler::Process(uint32_t frames_to_process) {
float detune_scale = DetuneToFrequencyMultiplier(detune);
frequency *= detune_scale;
ClampFrequency(&frequency, 1, Context()->sampleRate() / 2);
- periodic_wave_->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
- higher_wave_data,
- table_interpolation_factor);
+ periodic_wave->WaveDataForFundamentalFrequency(frequency, lower_wave_data,
+ higher_wave_data,
+ table_interpolation_factor);
}
float* phase_increments = phase_increments_.Data();
@@ -774,7 +781,7 @@ void OscillatorHandler::SetPeriodicWave(PeriodicWave* periodic_wave) {
}
bool OscillatorHandler::PropagatesSilence() const {
- return !IsPlayingOrScheduled() || HasFinished() || !periodic_wave_.Get();
+ return !IsPlayingOrScheduled() || HasFinished() || !periodic_wave_;
}
void OscillatorHandler::HandleStoppableSourceNode() {
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc
index 8e219f33d4a..a0d02c29390 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc
@@ -181,7 +181,8 @@ void PannerHandler::Process(uint32_t frames_to_process) {
}
// The audio thread can't block on this lock, so we call tryLock() instead.
- MutexTryLocker try_listener_locker(Listener()->ListenerLock());
+ auto listener = Listener();
+ MutexTryLocker try_listener_locker(listener->ListenerLock());
if (try_listener_locker.Locked()) {
if (!Context()->HasRealtimeConstraint() &&
@@ -189,11 +190,11 @@ void PannerHandler::Process(uint32_t frames_to_process) {
// For an OfflineAudioContext, we need to make sure the HRTFDatabase
// is loaded before proceeding. For realtime contexts, we don't
// have to wait. The HRTF panner handles that case itself.
- Listener()->WaitForHRTFDatabaseLoaderThreadCompletion();
+ listener->WaitForHRTFDatabaseLoaderThreadCompletion();
}
- if ((HasSampleAccurateValues() || Listener()->HasSampleAccurateValues()) &&
- (IsAudioRate() || Listener()->IsAudioRate())) {
+ if ((HasSampleAccurateValues() || listener->HasSampleAccurateValues()) &&
+ (IsAudioRate() || listener->IsAudioRate())) {
// It's tempting to skip sample-accurate processing if
// isAzimuthElevationDirty() and isDistanceConeGain() both return false.
// But in general we can't because something may scheduled to start in the
@@ -253,26 +254,27 @@ void PannerHandler::ProcessSampleAccurateValues(AudioBus* destination,
frames_to_process);
// Get the automation values from the listener.
+ auto listener = Listener();
const float* listener_x =
- Listener()->GetPositionXValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetPositionXValues(audio_utilities::kRenderQuantumFrames);
const float* listener_y =
- Listener()->GetPositionYValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetPositionYValues(audio_utilities::kRenderQuantumFrames);
const float* listener_z =
- Listener()->GetPositionZValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetPositionZValues(audio_utilities::kRenderQuantumFrames);
const float* forward_x =
- Listener()->GetForwardXValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetForwardXValues(audio_utilities::kRenderQuantumFrames);
const float* forward_y =
- Listener()->GetForwardYValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetForwardYValues(audio_utilities::kRenderQuantumFrames);
const float* forward_z =
- Listener()->GetForwardZValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetForwardZValues(audio_utilities::kRenderQuantumFrames);
const float* up_x =
- Listener()->GetUpXValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetUpXValues(audio_utilities::kRenderQuantumFrames);
const float* up_y =
- Listener()->GetUpYValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetUpYValues(audio_utilities::kRenderQuantumFrames);
const float* up_z =
- Listener()->GetUpZValues(audio_utilities::kRenderQuantumFrames);
+ listener->GetUpZValues(audio_utilities::kRenderQuantumFrames);
// Compute the azimuth, elevation, and total gains for each position.
double azimuth[audio_utilities::kRenderQuantumFrames];
@@ -327,9 +329,10 @@ void PannerHandler::Initialize() {
if (IsInitialized())
return;
+ auto listener = Listener();
panner_ = Panner::Create(panning_model_, Context()->sampleRate(),
- Listener()->HrtfDatabaseLoader());
- Listener()->AddPanner(*this);
+ listener->HrtfDatabaseLoader());
+ listener->AddPanner(*this);
// The panner is already marked as dirty, so |last_position_| and
// |last_orientation_| will bet updated on first use. Don't need to
@@ -343,17 +346,18 @@ void PannerHandler::Uninitialize() {
return;
panner_.reset();
- if (Listener()) {
+ auto listener = Listener();
+ if (listener) {
// Listener may have gone in the same garbage collection cycle, which means
// that the panner does not need to be removed.
- Listener()->RemovePanner(*this);
+ listener->RemovePanner(*this);
}
AudioHandler::Uninitialize();
}
-AudioListener* PannerHandler::Listener() {
- return listener_;
+CrossThreadPersistent<AudioListener> PannerHandler::Listener() const {
+ return listener_.Lock();
}
String PannerHandler::PanningModel() const {
@@ -625,13 +629,13 @@ void PannerHandler::AzimuthElevation(double* out_azimuth,
double* out_elevation) {
DCHECK(Context()->IsAudioThread());
+ auto listener = Listener();
// Calculate new azimuth and elevation if the panner or the listener changed
// position or orientation in any way.
- if (IsAzimuthElevationDirty() || Listener()->IsListenerDirty()) {
+ if (IsAzimuthElevationDirty() || listener->IsListenerDirty()) {
CalculateAzimuthElevation(&cached_azimuth_, &cached_elevation_,
- GetPosition(), Listener()->GetPosition(),
- Listener()->Orientation(),
- Listener()->UpVector());
+ GetPosition(), listener->GetPosition(),
+ listener->Orientation(), listener->UpVector());
is_azimuth_elevation_dirty_ = false;
}
@@ -642,11 +646,12 @@ void PannerHandler::AzimuthElevation(double* out_azimuth,
float PannerHandler::DistanceConeGain() {
DCHECK(Context()->IsAudioThread());
+ auto listener = Listener();
// Calculate new distance and cone gain if the panner or the listener
// changed position or orientation in any way.
- if (IsDistanceConeGainDirty() || Listener()->IsListenerDirty()) {
+ if (IsDistanceConeGainDirty() || listener->IsListenerDirty()) {
cached_distance_cone_gain_ = CalculateDistanceConeGain(
- GetPosition(), Orientation(), Listener()->GetPosition());
+ GetPosition(), Orientation(), listener->GetPosition());
is_distance_cone_gain_dirty_ = false;
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h
index 4161ec6f1ba..9987344c563 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h
@@ -133,7 +133,8 @@ class PannerHandler final : public AudioHandler {
AudioParamHandler& orientation_z);
// BaseAudioContext's listener
- AudioListener* Listener();
+ // AudioListener* Listener();
+ CrossThreadPersistent<AudioListener> Listener() const;
bool SetPanningModel(Panner::PanningModel); // Returns true on success.
bool SetDistanceModel(unsigned); // Returns true on success.
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc
new file mode 100644
index 00000000000..243177cc1b3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.cc
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium Authors. 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/realtime_audio_worklet_thread.h"
+
+#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+
+namespace blink {
+
+template class WorkletThreadHolder<RealtimeAudioWorkletThread>;
+
+int RealtimeAudioWorkletThread::s_ref_count_ = 0;
+
+RealtimeAudioWorkletThread::RealtimeAudioWorkletThread(
+ WorkerReportingProxy& worker_reporting_proxy)
+ : WorkerThread(worker_reporting_proxy) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "RealtimeAudioWorkletThread()");
+
+ DCHECK(IsMainThread());
+
+ ThreadCreationParams params =
+ ThreadCreationParams(ThreadType::kRealtimeAudioWorkletThread);
+
+ // TODO(crbug.com/1022888): The worklet thread priority is always NORMAL
+ // on OS_LINUX and OS_CHROMEOS regardless of the thread priority setting.
+ params.thread_priority = base::ThreadPriority::REALTIME_AUDIO;
+
+ if (++s_ref_count_ == 1)
+ EnsureSharedBackingThread(params);
+}
+
+RealtimeAudioWorkletThread::~RealtimeAudioWorkletThread() {
+ DCHECK(IsMainThread());
+ if (--s_ref_count_ == 0)
+ ClearSharedBackingThread();
+}
+
+WorkerBackingThread& RealtimeAudioWorkletThread::GetWorkerBackingThread() {
+ return *WorkletThreadHolder<RealtimeAudioWorkletThread>::GetInstance()
+ ->GetThread();
+}
+
+void RealtimeAudioWorkletThread::EnsureSharedBackingThread(
+ const ThreadCreationParams& params) {
+ DCHECK(IsMainThread());
+ WorkletThreadHolder<RealtimeAudioWorkletThread>::EnsureInstance(params);
+}
+
+void RealtimeAudioWorkletThread::ClearSharedBackingThread() {
+ DCHECK(IsMainThread());
+ CHECK_EQ(s_ref_count_, 0);
+ WorkletThreadHolder<RealtimeAudioWorkletThread>::ClearInstance();
+}
+
+WorkerOrWorkletGlobalScope* RealtimeAudioWorkletThread::CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams> creation_params) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "RealtimeAudioWorkletThread::CreateWorkerGlobalScope");
+ return MakeGarbageCollected<AudioWorkletGlobalScope>(
+ std::move(creation_params), this);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h b/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h
new file mode 100644
index 00000000000..5bd324ce422
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/realtime_audio_worklet_thread.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_REALTIME_AUDIO_WORKLET_THREAD_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_REALTIME_AUDIO_WORKLET_THREAD_H_
+
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class WorkerReportingProxy;
+struct ThreadCreationParams;
+
+// RealtimeAudioWorkletThread is a per-AudioWorkletGlobalScope object that has
+// a reference count to the backing thread that performs AudioWorklet tasks.
+// The backing thread uses REALTIME_AUDIO priority and the associated
+// AudioWorklet MUST be spawned from the top-level (main) frame.
+class MODULES_EXPORT RealtimeAudioWorkletThread final : public WorkerThread {
+ public:
+ explicit RealtimeAudioWorkletThread(WorkerReportingProxy&);
+ ~RealtimeAudioWorkletThread() final;
+
+ WorkerBackingThread& GetWorkerBackingThread() final;
+ void ClearWorkerBackingThread() final {}
+
+ static void EnsureSharedBackingThread(const ThreadCreationParams&);
+ static void ClearSharedBackingThread();
+
+ private:
+ WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams>) final;
+ bool IsOwningBackingThread() const final { return false; }
+ ThreadType GetThreadType() const final {
+ return ThreadType::kRealtimeAudioWorkletThread;
+ }
+
+ // Use for ref-counting of all RealtimeAudioWorkletThread instances in a
+ // process. Incremented by the constructor and decremented by destructor.
+ static int s_ref_count_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_REALTIME_AUDIO_WORKLET_THREAD_H_
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.cc
new file mode 100644
index 00000000000..b911c708dab
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.cc
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h"
+
+#include "third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+
+namespace blink {
+
+template class WorkletThreadHolder<SemiRealtimeAudioWorkletThread>;
+
+int SemiRealtimeAudioWorkletThread::s_ref_count_ = 0;
+
+SemiRealtimeAudioWorkletThread::SemiRealtimeAudioWorkletThread(
+ WorkerReportingProxy& worker_reporting_proxy)
+ : WorkerThread(worker_reporting_proxy) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "SemiRealtimeAudioWorklet()");
+
+ DCHECK(IsMainThread());
+
+ ThreadCreationParams params =
+ ThreadCreationParams(ThreadType::kSemiRealtimeAudioWorkletThread);
+
+ // TODO(crbug.com/1022888): The worklet thread priority is always NORMAL
+ // on OS_LINUX and OS_CHROMEOS regardless of this thread priority setting.
+ params.thread_priority = base::ThreadPriority::DISPLAY;
+
+ if (++s_ref_count_ == 1)
+ EnsureSharedBackingThread(params);
+}
+
+SemiRealtimeAudioWorkletThread::~SemiRealtimeAudioWorkletThread() {
+ DCHECK(IsMainThread());
+ if (--s_ref_count_ == 0)
+ ClearSharedBackingThread();
+}
+
+WorkerBackingThread& SemiRealtimeAudioWorkletThread::GetWorkerBackingThread() {
+ return *WorkletThreadHolder<SemiRealtimeAudioWorkletThread>::GetInstance()
+ ->GetThread();
+}
+
+void SemiRealtimeAudioWorkletThread::EnsureSharedBackingThread(
+ const ThreadCreationParams& params) {
+ DCHECK(IsMainThread());
+ WorkletThreadHolder<SemiRealtimeAudioWorkletThread>::EnsureInstance(params);
+}
+
+void SemiRealtimeAudioWorkletThread::ClearSharedBackingThread() {
+ DCHECK(IsMainThread());
+ CHECK_EQ(s_ref_count_, 0);
+ WorkletThreadHolder<SemiRealtimeAudioWorkletThread>::ClearInstance();
+}
+
+WorkerOrWorkletGlobalScope*
+SemiRealtimeAudioWorkletThread::CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams> creation_params) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"),
+ "SemiRealtimeAudioWorkletThread::CreateWorkerGlobalScope");
+ return MakeGarbageCollected<AudioWorkletGlobalScope>(
+ std::move(creation_params), this);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h b/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h
new file mode 100644
index 00000000000..937529c02de
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webaudio/semi_realtime_audio_worklet_thread.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_SEMI_REALTIME_AUDIO_WORKLET_THREAD_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_SEMI_REALTIME_AUDIO_WORKLET_THREAD_H_
+
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class WorkerReportingProxy;
+struct ThreadCreationParams;
+
+// SemiRealtimeAudioWorkletThread is a per-AudioWorkletGlobalScope object that
+// has a reference count to the backing thread that performs AudioWorklet tasks.
+// This object is used by an AudioWorklet spawned by non-MainFrame and its
+// backing thread has DISPLAY priority,
+class MODULES_EXPORT SemiRealtimeAudioWorkletThread final : public WorkerThread {
+ public:
+ explicit SemiRealtimeAudioWorkletThread(WorkerReportingProxy&);
+ ~SemiRealtimeAudioWorkletThread() final;
+
+ WorkerBackingThread& GetWorkerBackingThread() final;
+ void ClearWorkerBackingThread() final {}
+
+ static void EnsureSharedBackingThread(const ThreadCreationParams&);
+ static void ClearSharedBackingThread();
+
+ private:
+ WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
+ std::unique_ptr<GlobalScopeCreationParams>) final;
+ bool IsOwningBackingThread() const final { return false; }
+ ThreadType GetThreadType() const final {
+ return ThreadType::kSemiRealtimeAudioWorkletThread;
+ }
+
+ // Use for ref-counting of all SemiRealtimeAudioWorkletThread instances in a
+ // process. Incremented by the constructor and decremented by destructor.
+ static int s_ref_count_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_SEMI_REALTIME_AUDIO_WORKLET_THREAD_H_
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index 2b48c582307..99d0e47f9f0 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -53,6 +53,11 @@ blink_modules_sources("webcodecs") {
"//media/mojo:buildflags",
"//media/mojo/clients",
"//media/mojo/mojom",
+ "//third_party/libyuv:libyuv",
+ ]
+ public_deps = [
+ "//third_party/blink/renderer/modules/mediastream:mediastream",
+ "//third_party/blink/renderer/modules/webaudio:webaudio",
]
}
@@ -78,10 +83,14 @@ source_set("unit_tests") {
"//base/test:test_support",
"//gpu/command_buffer/common",
"//media:test_support",
+ "//media/mojo/services:services",
"//testing/gmock",
"//testing/gtest",
+ "//third_party/blink/public:test_headers",
+ "//third_party/blink/renderer/controller:blink_bindings_test_sources",
"//third_party/blink/renderer/modules",
"//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform:test_support",
"//third_party/blink/renderer/platform/wtf",
"//third_party/libyuv",
]
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/OWNERS b/chromium/third_party/blink/renderer/modules/webcodecs/OWNERS
index 08acd8d4733..3ee108f502d 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/OWNERS
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/OWNERS
@@ -2,4 +2,5 @@ mlamouri@chromium.org
sandersd@chromium.org
dalecurtis@chromium.org
chcunningham@chromium.org
-tguilbert@chromium.org \ No newline at end of file
+tguilbert@chromium.org
+eugene@chromium.org \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
index 419bc929f78..4b9f7fa68c5 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.cc
@@ -64,7 +64,7 @@ class MediaAudioTaskWrapper {
WTF::CrossThreadOnceFunction<void(media::Status status,
base::Optional<DecoderDetails>)>;
using CrossThreadOnceDecodeCB =
- WTF::CrossThreadOnceFunction<void(media::DecodeStatus)>;
+ WTF::CrossThreadOnceFunction<void(media::Status)>;
using CrossThreadOnceResetCB = WTF::CrossThreadOnceClosure;
MediaAudioTaskWrapper(
@@ -217,13 +217,13 @@ class MediaAudioTaskWrapper {
weak_client_, std::move(buffer)));
}
- void OnDecodeDone(int cb_id, media::DecodeStatus status) {
+ void OnDecodeDone(int cb_id, media::Status status) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
WTF::CrossThreadBindOnce(&CrossThreadAudioDecoderClient::OnDecodeDone,
- weak_client_, cb_id, status));
+ weak_client_, cb_id, std::move(status)));
}
void OnReset(int cb_id) {
@@ -347,7 +347,7 @@ void AudioDecoderBroker::Decode(scoped_refptr<media::DecoderBuffer> buffer,
buffer, callback_id));
}
-void AudioDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
+void AudioDecoderBroker::OnDecodeDone(int cb_id, media::Status status) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(pending_decode_cb_map_.Contains(cb_id));
@@ -358,7 +358,7 @@ void AudioDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
// Do this last. Caller may destruct |this| in response to the callback while
// this method is still on the stack.
- std::move(decode_cb).Run(status);
+ std::move(decode_cb).Run(std::move(status));
}
void AudioDecoderBroker::Reset(base::OnceClosure reset_cb) {
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
index 1bae54ee91d..c99ade47400 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h
@@ -41,7 +41,7 @@ class CrossThreadAudioDecoderClient {
virtual void OnInitialize(media::Status status,
base::Optional<DecoderDetails> details) = 0;
- virtual void OnDecodeDone(int cb_id, media::DecodeStatus status) = 0;
+ virtual void OnDecodeDone(int cb_id, media::Status status) = 0;
virtual void OnDecodeOutput(scoped_refptr<media::AudioBuffer> buffer) = 0;
@@ -91,7 +91,7 @@ class MODULES_EXPORT AudioDecoderBroker : public media::AudioDecoder,
// MediaAudioTaskWrapper::CrossThreadAudioDecoderClient
void OnInitialize(media::Status status,
base::Optional<DecoderDetails> details) override;
- void OnDecodeDone(int cb_id, media::DecodeStatus status) override;
+ void OnDecodeDone(int cb_id, media::Status status) override;
void OnDecodeOutput(scoped_refptr<media::AudioBuffer> buffer) override;
void OnReset(int cb_id) override;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
index 1c941199d4f..3d7115ae983 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/audio_decoder_broker_test.cc
@@ -160,8 +160,8 @@ class AudioDecoderBrokerTest : public testing::Test {
done_cb.Run();
}
void OnDecodeDoneWithClosure(base::RepeatingClosure done_cb,
- media::DecodeStatus status) {
- OnDecodeDone(status);
+ media::Status status) {
+ OnDecodeDone(std::move(status));
done_cb.Run();
}
@@ -171,7 +171,7 @@ class AudioDecoderBrokerTest : public testing::Test {
}
MOCK_METHOD1(OnInit, void(media::Status status));
- MOCK_METHOD1(OnDecodeDone, void(media::DecodeStatus));
+ MOCK_METHOD1(OnDecodeDone, void(media::Status));
MOCK_METHOD0(OnResetDone, void());
void OnOutput(scoped_refptr<media::AudioBuffer> buffer) {
@@ -210,9 +210,9 @@ class AudioDecoderBrokerTest : public testing::Test {
void DecodeBuffer(
scoped_refptr<media::DecoderBuffer> buffer,
- media::DecodeStatus expected_status = media::DecodeStatus::OK) {
+ media::StatusCode expected_status = media::StatusCode::kOk) {
base::RunLoop run_loop;
- EXPECT_CALL(*this, OnDecodeDone(expected_status));
+ EXPECT_CALL(*this, OnDecodeDone(HasStatusCode(expected_status)));
decoder_broker_->Decode(
buffer, WTF::Bind(&AudioDecoderBrokerTest::OnDecodeDoneWithClosure,
WTF::Unretained(this), run_loop.QuitClosure()));
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
index 47772f51478..533c72d76b4 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -382,7 +382,7 @@ void DecoderTemplate<Traits>::Shutdown(bool is_error) {
}
template <typename Traits>
-void DecoderTemplate<Traits>::OnConfigureFlushDone(media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnConfigureFlushDone(media::Status status) {
DVLOG(3) << __func__;
if (IsClosed())
return;
@@ -390,7 +390,7 @@ void DecoderTemplate<Traits>::OnConfigureFlushDone(media::DecodeStatus status) {
DCHECK(pending_request_);
DCHECK_EQ(pending_request_->type, Request::Type::kConfigure);
- if (status != media::DecodeStatus::OK) {
+ if (!status.is_ok()) {
HandleError();
return;
}
@@ -425,14 +425,12 @@ void DecoderTemplate<Traits>::OnInitializeDone(media::Status status) {
}
template <typename Traits>
-void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id,
- media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id, media::Status status) {
DVLOG(3) << __func__;
if (IsClosed())
return;
- if (status != media::DecodeStatus::OK &&
- status != media::DecodeStatus::ABORTED) {
+ if (!status.is_ok() && status.code() != media::StatusCode::kAborted) {
HandleError();
return;
}
@@ -444,7 +442,7 @@ void DecoderTemplate<Traits>::OnDecodeDone(uint32_t id,
}
template <typename Traits>
-void DecoderTemplate<Traits>::OnFlushDone(media::DecodeStatus status) {
+void DecoderTemplate<Traits>::OnFlushDone(media::Status status) {
DVLOG(3) << __func__;
if (IsClosed())
return;
@@ -452,7 +450,7 @@ void DecoderTemplate<Traits>::OnFlushDone(media::DecodeStatus status) {
DCHECK(pending_request_);
DCHECK_EQ(pending_request_->type, Request::Type::kFlush);
- if (status != media::DecodeStatus::OK) {
+ if (!status.is_ok()) {
HandleError();
return;
}
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h
index 6369944ee1f..6ec96411fb8 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/decoder_template.h
@@ -99,9 +99,9 @@ class MODULES_EXPORT DecoderTemplate : public ScriptWrappable {
// Called by |decoder_|.
void OnInitializeDone(media::Status status);
- void OnDecodeDone(uint32_t id, media::DecodeStatus);
- void OnFlushDone(media::DecodeStatus);
- void OnConfigureFlushDone(media::DecodeStatus);
+ void OnDecodeDone(uint32_t id, media::Status);
+ void OnFlushDone(media::Status);
+ void OnConfigureFlushDone(media::Status);
void OnResetDone();
void OnOutput(scoped_refptr<MediaOutputType>);
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
index d88a46ff025..86677a08b96 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
@@ -17,8 +17,10 @@ EncodedVideoChunk* EncodedVideoChunk::Create(EncodedVideoChunkInit* init) {
EncodedVideoMetadata metadata;
metadata.timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
metadata.key_frame = (init->type() == "key");
- if (init->hasDuration())
- metadata.duration = base::TimeDelta::FromMicroseconds(init->duration());
+ if (init->hasDurationNonNull()) {
+ metadata.duration =
+ base::TimeDelta::FromMicroseconds(init->durationNonNull());
+ }
DOMArrayPiece piece(init->data());
// A full copy of the data happens here.
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc
index 33c2646dd98..ec4ad8d9ef3 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_test.cc
@@ -5,7 +5,7 @@
#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni b/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
index 1d1895aad39..0dbbb215af8 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -41,7 +41,10 @@ modules_dictionary_idl_files = [
"video_track_writer_parameters.idl",
]
-modules_typedefs_enums_only_idl_files = [ "codec_state.idl" ]
+modules_typedefs_enums_only_idl_files = [
+ "codec_state.idl",
+ "video_pixel_format.idl",
+]
# IDL files that either define partial interfaces or target (right side of)
# `includes`.
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
index b8ae5c07a53..f9c18a7e8e1 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
@@ -120,9 +120,8 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
return;
}
- // TODO(crbug.com/1073995): Data is owned by the caller who may be free to
- // manipulate it. We will probably need to make a copy to our own internal
- // data or neuter the buffers as seen by JS.
+ // Since data is owned by the caller who may be free to manipulate it, we must
+ // check HasValidEncodedData() before attempting to access |decoder_|.
segment_reader_ = SegmentReader::CreateFromSkData(
SkData::MakeWithoutCopy(buffer.Data(), buffer.ByteLengthAsSizeT()));
if (!segment_reader_) {
@@ -266,6 +265,7 @@ void ImageDecoderExternal::Trace(Visitor* visitor) const {
void ImageDecoderExternal::CreateImageDecoder() {
DCHECK(!decoder_);
+ DCHECK(HasValidEncodedData());
// TODO(crbug.com/1073995): We should probably call
// ImageDecoder::SetMemoryAllocator() so that we can recycle frame buffers for
@@ -320,6 +320,13 @@ void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
continue;
}
+ if (!HasValidEncodedData()) {
+ request->exception = MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kInvalidStateError,
+ "Source data has been neutered");
+ continue;
+ }
+
auto* image = decoder_->DecodeFrameBufferAtIndex(request->frame_index);
if (decoder_->Failed() || !image) {
// TODO(crbug.com/1073995): Include frameIndex in rejection?
@@ -398,6 +405,7 @@ void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
}
void ImageDecoderExternal::MaybeSatisfyPendingMetadataDecodes() {
+ DCHECK(HasValidEncodedData());
DCHECK(decoder_);
if (!decoder_->IsSizeAvailable() && !decoder_->Failed())
return;
@@ -409,6 +417,9 @@ void ImageDecoderExternal::MaybeSatisfyPendingMetadataDecodes() {
}
void ImageDecoderExternal::MaybeUpdateMetadata() {
+ if (!HasValidEncodedData())
+ return;
+
// Since we always create the decoder at construction, we need to wait until
// at least the size is available before signaling that metadata has been
// retrieved.
@@ -461,4 +472,22 @@ void ImageDecoderExternal::MaybeUpdateMetadata() {
MaybeSatisfyPendingMetadataDecodes();
}
+bool ImageDecoderExternal::HasValidEncodedData() const {
+ // If we keep an internal copy of the data, it's always valid.
+ if (stream_buffer_)
+ return true;
+
+ if (init_data_->data().IsArrayBuffer() &&
+ init_data_->data().GetAsArrayBuffer()->IsDetached()) {
+ return false;
+ }
+
+ if (init_data_->data().IsArrayBufferView() &&
+ !init_data_->data().GetAsArrayBufferView()->BaseAddress()) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h
index 88fff55e909..f3f6dd8b202 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h
@@ -66,6 +66,10 @@ class MODULES_EXPORT ImageDecoderExternal final : public ScriptWrappable,
void MaybeSatisfyPendingMetadataDecodes();
void MaybeUpdateMetadata();
+ // Returns false if the decoder was constructed with an ArrayBuffer or
+ // ArrayBufferView that has since been neutered.
+ bool HasValidEncodedData() const;
+
Member<ScriptState> script_state_;
// Used when a ReadableStream is provided.
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
index dcbcc047e5c..2d38acec5c3 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
@@ -98,6 +98,57 @@ TEST_F(ImageDecoderTest, DecodeEmpty) {
EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
}
+TEST_F(ImageDecoderTest, DecodeNeuteredAtConstruction) {
+ V8TestingScope v8_scope;
+
+ auto* init = MakeGarbageCollected<ImageDecoderInit>();
+ auto* buffer = DOMArrayBuffer::Create(SharedBuffer::Create());
+
+ init->setType("image/png");
+ init->setData(
+ ArrayBufferOrArrayBufferViewOrReadableStream::FromArrayBuffer(buffer));
+
+ ArrayBufferContents contents;
+ ASSERT_TRUE(buffer->Transfer(v8_scope.GetIsolate(), contents));
+
+ auto* decoder = ImageDecoderExternal::Create(v8_scope.GetScriptState(), init,
+ v8_scope.GetExceptionState());
+ EXPECT_TRUE(decoder);
+ EXPECT_TRUE(v8_scope.GetExceptionState().HadException());
+}
+
+TEST_F(ImageDecoderTest, DecodeNeuteredAtDecodeTime) {
+ V8TestingScope v8_scope;
+
+ constexpr char kImageType[] = "image/gif";
+ EXPECT_TRUE(ImageDecoderExternal::canDecodeType(kImageType));
+
+ auto* init = MakeGarbageCollected<ImageDecoderInit>();
+ init->setType(kImageType);
+
+ constexpr char kTestFile[] = "images/resources/animated.gif";
+ auto data = ReadFile(kTestFile);
+ DCHECK(!data->IsEmpty()) << "Missing file: " << kTestFile;
+
+ auto* buffer = DOMArrayBuffer::Create(std::move(data));
+
+ init->setData(
+ ArrayBufferOrArrayBufferViewOrReadableStream::FromArrayBuffer(buffer));
+
+ auto* decoder = ImageDecoderExternal::Create(v8_scope.GetScriptState(), init,
+ v8_scope.GetExceptionState());
+ ASSERT_TRUE(decoder);
+ ASSERT_FALSE(v8_scope.GetExceptionState().HadException());
+
+ ArrayBufferContents contents;
+ ASSERT_TRUE(buffer->Transfer(v8_scope.GetIsolate(), contents));
+
+ auto promise = decoder->decode(0, true);
+ ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
+ tester.WaitUntilSettled();
+ ASSERT_TRUE(tester.IsRejected());
+}
+
TEST_F(ImageDecoderTest, DecodeUnsupported) {
V8TestingScope v8_scope;
constexpr char kImageType[] = "image/svg+xml";
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
index 3e138124720..2a79ab138ae 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.cc
@@ -70,7 +70,7 @@ class MediaVideoTaskWrapper {
WTF::CrossThreadOnceFunction<void(media::Status status,
base::Optional<DecoderDetails>)>;
using CrossThreadOnceDecodeCB =
- WTF::CrossThreadOnceFunction<void(media::DecodeStatus)>;
+ WTF::CrossThreadOnceFunction<void(const media::Status&)>;
using CrossThreadOnceResetCB = WTF::CrossThreadOnceClosure;
MediaVideoTaskWrapper(
@@ -190,18 +190,26 @@ class MediaVideoTaskWrapper {
std::move(external_decoder_factory));
}
- std::vector<std::unique_ptr<media::VideoDecoder>> OnCreateDecoders() {
+ void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
+ media::ProvideOverlayInfoCB overlay_info_cb) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // TODO(chcunningham): Add plumbing to enable overlays on Android. See
- // handling in WebMediaPlayerImpl.
- media::RequestOverlayInfoCB request_overlay_info_cb;
+ // Android overlays are not supported.
+ if (overlay_info_cb)
+ std::move(overlay_info_cb).Run(media::OverlayInfo());
+ }
+
+ std::vector<std::unique_ptr<media::VideoDecoder>> OnCreateDecoders() {
+ DVLOG(2) << __func__;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::unique_ptr<media::VideoDecoder>> video_decoders;
decoder_factory_->CreateVideoDecoders(
media_task_runner_, gpu_factories_, &null_media_log_,
- request_overlay_info_cb, target_color_space_, &video_decoders);
+ WTF::BindRepeating(&MediaVideoTaskWrapper::OnRequestOverlayInfo,
+ weak_factory_.GetWeakPtr()),
+ target_color_space_, &video_decoders);
return video_decoders;
}
@@ -244,14 +252,14 @@ class MediaVideoTaskWrapper {
decoder_->CanReadWithoutStalling()));
}
- void OnDecodeDone(int cb_id, media::DecodeStatus status) {
+ void OnDecodeDone(int cb_id, media::Status status) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
WTF::CrossThreadBindOnce(&CrossThreadVideoDecoderClient::OnDecodeDone,
- weak_client_, cb_id, status));
+ weak_client_, cb_id, std::move(status)));
}
void OnReset(int cb_id) {
@@ -390,7 +398,7 @@ void VideoDecoderBroker::Decode(scoped_refptr<media::DecoderBuffer> buffer,
buffer, callback_id));
}
-void VideoDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
+void VideoDecoderBroker::OnDecodeDone(int cb_id, media::Status status) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(pending_decode_cb_map_.Contains(cb_id));
@@ -401,7 +409,7 @@ void VideoDecoderBroker::OnDecodeDone(int cb_id, media::DecodeStatus status) {
// Do this last. Caller may destruct |this| in response to the callback while
// this method is still on the stack.
- std::move(decode_cb).Run(status);
+ std::move(decode_cb).Run(std::move(status));
}
void VideoDecoderBroker::Reset(base::OnceClosure reset_cb) {
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
index a2e461c2929..62115c4b520 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h
@@ -50,7 +50,7 @@ class CrossThreadVideoDecoderClient {
virtual void OnInitialize(media::Status status,
base::Optional<DecoderDetails> details) = 0;
- virtual void OnDecodeDone(int cb_id, media::DecodeStatus status) = 0;
+ virtual void OnDecodeDone(int cb_id, media::Status status) = 0;
virtual void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame,
bool can_read_without_stalling) = 0;
@@ -107,7 +107,7 @@ class MODULES_EXPORT VideoDecoderBroker : public media::VideoDecoder,
// MediaVideoTaskWrapper::CrossThreadVideoDecoderClient
void OnInitialize(media::Status status,
base::Optional<DecoderDetails> details) override;
- void OnDecodeDone(int cb_id, media::DecodeStatus status) override;
+ void OnDecodeDone(int cb_id, media::Status status) override;
void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame,
bool can_read_without_stalling) override;
void OnReset(int cb_id) override;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
index 8c26091d6da..97ec506c5d9 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_decoder_broker_test.cc
@@ -169,8 +169,8 @@ class VideoDecoderBrokerTest : public testing::Test {
done_cb.Run();
}
void OnDecodeDoneWithClosure(base::RepeatingClosure done_cb,
- media::DecodeStatus status) {
- OnDecodeDone(status);
+ media::Status status) {
+ OnDecodeDone(std::move(status));
done_cb.Run();
}
@@ -180,7 +180,7 @@ class VideoDecoderBrokerTest : public testing::Test {
}
MOCK_METHOD1(OnInit, void(media::Status status));
- MOCK_METHOD1(OnDecodeDone, void(media::DecodeStatus));
+ MOCK_METHOD1(OnDecodeDone, void(media::Status));
MOCK_METHOD0(OnResetDone, void());
void OnOutput(scoped_refptr<media::VideoFrame> frame) {
@@ -238,9 +238,9 @@ class VideoDecoderBrokerTest : public testing::Test {
void DecodeBuffer(
scoped_refptr<media::DecoderBuffer> buffer,
- media::DecodeStatus expected_status = media::DecodeStatus::OK) {
+ media::StatusCode expected_status = media::StatusCode::kOk) {
base::RunLoop run_loop;
- EXPECT_CALL(*this, OnDecodeDone(expected_status));
+ EXPECT_CALL(*this, OnDecodeDone(HasStatusCode(expected_status)));
decoder_broker_->Decode(
buffer, WTF::Bind(&VideoDecoderBrokerTest::OnDecodeDoneWithClosure,
WTF::Unretained(this), run_loop.QuitClosure()));
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 3cc3a4b6972..e30c10a9533 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -10,10 +10,14 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "build/build_config.h"
#include "media/base/mime_util.h"
#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
#include "media/base/video_encoder.h"
+#if BUILDFLAG(ENABLE_OPENH264)
+#include "media/video/openh264_video_encoder.h"
+#endif
#if BUILDFLAG(ENABLE_LIBVPX)
#include "media/video/vpx_video_encoder.h"
#endif
@@ -26,6 +30,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_encode_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_init.h"
@@ -45,16 +50,54 @@
namespace blink {
namespace {
-std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder() {
+std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder(
+ media::VideoCodecProfile profile,
+ const media::VideoEncoder::Options& options) {
+#if defined(OS_MAC) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+ // TODO(https://crbug.com/1110279) Flush() is not implemented on MacOS'
+ // accelerated video encoder, so we can't use it yet.
+ return nullptr;
+#else
auto* gpu_factories = Platform::Current()->GetGpuFactories();
if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled())
return nullptr;
+ auto supported_profiles =
+ gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles().value_or(
+ media::VideoEncodeAccelerator::SupportedProfiles());
+
+ bool found_supported_profile = false;
+ for (auto& supported_profile : supported_profiles) {
+ if (supported_profile.profile != profile)
+ continue;
+
+ if (supported_profile.min_resolution.width() > options.width ||
+ supported_profile.min_resolution.height() > options.height)
+ continue;
+
+ if (supported_profile.max_resolution.width() < options.width ||
+ supported_profile.max_resolution.height() < options.height)
+ continue;
+
+ double max_supported_framerate =
+ double{supported_profile.max_framerate_numerator} /
+ supported_profile.max_framerate_denominator;
+ if (options.framerate > max_supported_framerate)
+ continue;
+
+ found_supported_profile = true;
+ break;
+ }
+
+ if (!found_supported_profile)
+ return nullptr;
+
auto task_runner = Thread::MainThread()->GetTaskRunner();
return std::make_unique<
media::AsyncDestroyVideoEncoder<media::VideoEncodeAcceleratorAdapter>>(
std::make_unique<media::VideoEncodeAcceleratorAdapter>(
gpu_factories, std::move(task_runner)));
+#endif // defined(OS_MAC) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
}
std::unique_ptr<media::VideoEncoder> CreateVpxVideoEncoder() {
@@ -65,6 +108,14 @@ std::unique_ptr<media::VideoEncoder> CreateVpxVideoEncoder() {
#endif // BUILDFLAG(ENABLE_LIBVPX)
}
+std::unique_ptr<media::VideoEncoder> CreateOpenH264VideoEncoder() {
+#if BUILDFLAG(ENABLE_OPENH264)
+ return std::make_unique<media::OpenH264VideoEncoder>();
+#else
+ return nullptr;
+#endif // BUILDFLAG(ENABLE_OPENH264)
+}
+
scoped_refptr<media::VideoFrame> ConvertToI420Frame(
scoped_refptr<media::VideoFrame> frame) {
DCHECK_EQ(frame->storage_type(),
@@ -129,16 +180,19 @@ int32_t VideoEncoder::encodeQueueSize() {
std::unique_ptr<VideoEncoder::ParsedConfig> VideoEncoder::ParseConfig(
const VideoEncoderConfig* config,
ExceptionState& exception_state) {
+ constexpr int kMaxSupportedFrameSize = 8000;
auto parsed = std::make_unique<ParsedConfig>();
parsed->options.height = config->height();
- if (parsed->options.height == 0) {
+ if (parsed->options.height == 0 ||
+ parsed->options.height > kMaxSupportedFrameSize) {
exception_state.ThrowTypeError("Invalid height.");
return nullptr;
}
parsed->options.width = config->width();
- if (parsed->options.width == 0) {
+ if (parsed->options.width == 0 ||
+ parsed->options.width > kMaxSupportedFrameSize) {
exception_state.ThrowTypeError("Invalid width.");
return nullptr;
}
@@ -167,6 +221,7 @@ std::unique_ptr<VideoEncoder::ParsedConfig> VideoEncoder::ParseConfig(
parsed->profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
parsed->color_space = media::VideoColorSpace::REC709();
parsed->level = 0;
+ parsed->codec_string = config->codec();
bool parse_succeeded = media::ParseVideoCodecString(
"", config->codec().Utf8(), &is_codec_ambiguous, &parsed->codec,
@@ -215,11 +270,6 @@ bool VideoEncoder::VerifyCodecSupport(ParsedConfig* config,
break;
case media::kCodecH264:
- if (config->acc_pref == AccelerationPreference::kDeny) {
- exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
- "Software h264 is not supported yet");
- return false;
- }
break;
default:
@@ -231,6 +281,46 @@ bool VideoEncoder::VerifyCodecSupport(ParsedConfig* config,
return true;
}
+std::unique_ptr<media::VideoEncoder> VideoEncoder::CreateMediaVideoEncoder(
+ const ParsedConfig& config) {
+ // TODO(https://crbug.com/1119636): Implement / call a proper method for
+ // detecting support of encoder configs.
+ switch (config.acc_pref) {
+ case AccelerationPreference::kRequire:
+ return CreateAcceleratedVideoEncoder(config.profile, config.options);
+ case AccelerationPreference::kAllow: {
+ auto result =
+ CreateAcceleratedVideoEncoder(config.profile, config.options);
+ if (result)
+ return result;
+ switch (config.codec) {
+ case media::kCodecVP8:
+ case media::kCodecVP9:
+ return CreateVpxVideoEncoder();
+ case media::kCodecH264:
+ return CreateOpenH264VideoEncoder();
+ default:
+ return nullptr;
+ }
+ }
+ case AccelerationPreference::kDeny: {
+ switch (config.codec) {
+ case media::kCodecVP8:
+ case media::kCodecVP9:
+ return CreateVpxVideoEncoder();
+ case media::kCodecH264:
+ return CreateOpenH264VideoEncoder();
+ default:
+ return nullptr;
+ }
+ }
+
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
void VideoEncoder::configure(const VideoEncoderConfig* config,
ExceptionState& exception_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -257,7 +347,7 @@ void VideoEncoder::configure(const VideoEncoderConfig* config,
Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kConfigure;
- request->config = std::move(parsed_config);
+ active_config_ = std::move(parsed_config);
EnqueueRequest(request);
}
@@ -283,8 +373,10 @@ void VideoEncoder::encode(VideoFrame* frame,
return;
}
- if (internal_frame->cropWidth() != uint32_t{frame_size_.width()} ||
- internal_frame->cropHeight() != uint32_t{frame_size_.height()}) {
+ DCHECK(active_config_);
+ if (internal_frame->cropWidth() != uint32_t{active_config_->options.width} ||
+ internal_frame->cropHeight() !=
+ uint32_t{active_config_->options.height}) {
exception_state.ThrowDOMException(
DOMExceptionCode::kOperationError,
"Frame size doesn't match initial encoder parameters.");
@@ -294,8 +386,8 @@ void VideoEncoder::encode(VideoFrame* frame,
return;
}
- // At this point, we have "consumed" the frame, and will destroy the clone in
- // ProcessEncode().
+ // At this point, we have "consumed" the frame, and will destroy the clone
+ // in ProcessEncode().
frame->destroy();
Request* request = MakeGarbageCollected<Request>();
@@ -360,14 +452,6 @@ void VideoEncoder::ClearRequests() {
}
}
-void VideoEncoder::CallOutputCallback(EncodedVideoChunk* chunk) {
- if (!script_state_->ContextIsValid() || !output_callback_ ||
- state_.AsEnum() != V8CodecState::Enum::kConfigured)
- return;
- ScriptState::Scope scope(script_state_);
- output_callback_->InvokeAndReportException(nullptr, chunk);
-}
-
void VideoEncoder::HandleError(DOMException* ex) {
// Save a temp before we clear the callback.
V8WebCodecsErrorCallback* error_callback = error_callback_.Get();
@@ -453,44 +537,26 @@ void VideoEncoder::ProcessEncode(Request* request) {
WTF::Bind(done_callback, WrapWeakPersistent(this),
WrapPersistentIfNeeded(request)));
- // We passed a copy of frame() above, so this should be safe to destroy here.
+ // We passed a copy of frame() above, so this should be safe to destroy
+ // here.
request->frame->destroy();
}
void VideoEncoder::ProcessConfigure(Request* request) {
DCHECK_NE(state_.AsEnum(), V8CodecState::Enum::kClosed);
- DCHECK(request->config);
DCHECK_EQ(request->type, Request::Type::kConfigure);
+ DCHECK(active_config_);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto config = std::move(request->config);
-
- switch (config->codec) {
- case media::kCodecVP8:
- case media::kCodecVP9:
- media_encoder_ = CreateVpxVideoEncoder();
- break;
-
- case media::kCodecH264:
- media_encoder_ = CreateAcceleratedVideoEncoder();
- break;
-
- default:
- // This should already have been caught in ParseConfig() and
- // VerifyCodecSupport().
- NOTREACHED();
- break;
- }
-
+ media_encoder_ = CreateMediaVideoEncoder(*active_config_);
if (!media_encoder_) {
- // CreateAcceleratedVideoEncoder() can return a nullptr.
- HandleError(DOMExceptionCode::kOperationError, "Encoder creation error.");
+ HandleError(DOMExceptionCode::kOperationError,
+ "Encoder creation error. Most likely unsupported "
+ "codec/acceleration requirement combination.");
return;
}
- frame_size_ = gfx::Size(config->options.width, config->options.height);
-
- auto output_cb = WTF::BindRepeating(&VideoEncoder::MediaEncoderOutputCallback,
+ auto output_cb = WTF::BindRepeating(&VideoEncoder::CallOutputCallback,
WrapWeakPersistent(this));
auto done_callback = [](VideoEncoder* self, Request* req,
@@ -498,16 +564,20 @@ void VideoEncoder::ProcessConfigure(Request* request) {
if (!self)
return;
DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_);
+ DCHECK(self->active_config_);
+
if (!status.is_ok()) {
std::string msg = "Encoder initialization error: " + status.message();
self->HandleError(DOMExceptionCode::kOperationError, msg.c_str());
}
+
self->stall_request_processing_ = false;
self->ProcessRequests();
};
stall_request_processing_ = true;
- media_encoder_->Initialize(config->profile, config->options, output_cb,
+ media_encoder_->Initialize(active_config_->profile, active_config_->options,
+ std::move(output_cb),
WTF::Bind(done_callback, WrapWeakPersistent(this),
WrapPersistent(request)));
}
@@ -542,8 +612,13 @@ void VideoEncoder::ProcessFlush(Request* request) {
WrapPersistentIfNeeded(request)));
}
-void VideoEncoder::MediaEncoderOutputCallback(
- media::VideoEncoderOutput output) {
+void VideoEncoder::CallOutputCallback(
+ media::VideoEncoderOutput output,
+ base::Optional<media::VideoEncoder::CodecDescription> codec_desc) {
+ if (!script_state_->ContextIsValid() || !output_callback_ ||
+ state_.AsEnum() != V8CodecState::Enum::kConfigured)
+ return;
+
EncodedVideoMetadata metadata;
metadata.timestamp = output.timestamp;
metadata.key_frame = output.key_frame;
@@ -553,7 +628,21 @@ void VideoEncoder::MediaEncoderOutputCallback(
ArrayBufferContents data(output.data.release(), output.size, deleter);
auto* dom_array = MakeGarbageCollected<DOMArrayBuffer>(std::move(data));
auto* chunk = MakeGarbageCollected<EncodedVideoChunk>(metadata, dom_array);
- CallOutputCallback(chunk);
+
+ DCHECK(active_config_);
+ VideoDecoderConfig* decoder_config =
+ MakeGarbageCollected<VideoDecoderConfig>();
+ decoder_config->setCodec(active_config_->codec_string);
+ decoder_config->setCodedHeight(active_config_->options.height);
+ decoder_config->setCodedWidth(active_config_->options.width);
+ if (codec_desc.has_value()) {
+ auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(),
+ codec_desc.value().size());
+ decoder_config->setDescription(
+ ArrayBufferOrArrayBufferView::FromArrayBuffer(desc_array_buf));
+ }
+ ScriptState::Scope scope(script_state_);
+ output_callback_->InvokeAndReportException(nullptr, chunk, decoder_config);
}
void VideoEncoder::Trace(Visitor* visitor) const {
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h
index 5d5b8638f7a..e147db13893 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -69,8 +69,6 @@ class MODULES_EXPORT VideoEncoder final : public ScriptWrappable {
// TODO(ezemtsov): Replace this with a {Audio|Video}EncoderConfig.
struct ParsedConfig final {
- void Trace(Visitor*) const;
-
media::VideoCodec codec;
media::VideoCodecProfile profile;
uint8_t level;
@@ -79,6 +77,7 @@ class MODULES_EXPORT VideoEncoder final : public ScriptWrappable {
AccelerationPreference acc_pref;
media::VideoEncoder::Options options;
+ String codec_string;
};
struct Request final : public GarbageCollected<Request> {
@@ -91,13 +90,14 @@ class MODULES_EXPORT VideoEncoder final : public ScriptWrappable {
void Trace(Visitor*) const;
Type type;
- std::unique_ptr<ParsedConfig> config; // used by kConfigure
Member<VideoFrame> frame; // used by kEncode
Member<const VideoEncoderEncodeOptions> encodeOpts; // used by kEncode
Member<ScriptPromiseResolver> resolver; // used by kFlush
};
- void CallOutputCallback(EncodedVideoChunk* chunk);
+ void CallOutputCallback(
+ media::VideoEncoderOutput output,
+ base::Optional<media::VideoEncoder::CodecDescription> codec_desc);
void HandleError(DOMException* ex);
void HandleError(DOMExceptionCode code, const String& message);
void EnqueueRequest(Request* request);
@@ -108,13 +108,13 @@ class MODULES_EXPORT VideoEncoder final : public ScriptWrappable {
void ClearRequests();
- void MediaEncoderOutputCallback(media::VideoEncoderOutput output);
-
std::unique_ptr<ParsedConfig> ParseConfig(const VideoEncoderConfig*,
ExceptionState&);
bool VerifyCodecSupport(ParsedConfig*, ExceptionState&);
+ std::unique_ptr<media::VideoEncoder> CreateMediaVideoEncoder(
+ const ParsedConfig& config);
- gfx::Size frame_size_;
+ std::unique_ptr<ParsedConfig> active_config_;
std::unique_ptr<media::VideoEncoder> media_encoder_;
V8CodecState state_;
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl
index 22235963ef9..f09eb321c64 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl
@@ -5,4 +5,5 @@
// https://github.com/WICG/web-codecs
// Handles a new encoded video chunk on the consumer side of the video encoder.
-callback VideoEncoderOutputCallback = void (EncodedVideoChunk chunk); \ No newline at end of file
+callback VideoEncoderOutputCallback =
+ void (EncodedVideoChunk chunk, VideoDecoderConfig decoder_config); \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index ac74047a546..c2122769290 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -12,10 +12,12 @@
#include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_metadata.h"
+#include "media/base/wait_and_replace_sync_token_client.h"
#include "media/renderers/paint_canvas_video_renderer.h"
-#include "media/renderers/yuv_util.h"
+#include "media/renderers/video_frame_yuv_converter.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_pixel_format.h"
#include "third_party/blink/renderer/core/html/canvas/image_data.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h"
@@ -94,9 +96,9 @@ VideoFrame* VideoFrame::Create(ImageBitmap* source,
base::TimeDelta timestamp =
base::TimeDelta::FromMicroseconds(init->timestamp());
- auto sk_image =
- source->BitmapImage()->PaintImageForCurrentFrame().GetSkImage();
- auto sk_color_space = sk_image->refColorSpace();
+ auto sk_image_info =
+ source->BitmapImage()->PaintImageForCurrentFrame().GetSkImageInfo();
+ auto sk_color_space = sk_image_info.refColorSpace();
if (!sk_color_space) {
sk_color_space = SkColorSpace::MakeSRGB();
}
@@ -105,7 +107,7 @@ VideoFrame* VideoFrame::Create(ImageBitmap* source,
"Invalid color space");
return nullptr;
}
- auto sk_color_type = sk_image->colorType();
+ auto sk_color_type = sk_image_info.colorType();
if (!IsValidSkColorType(sk_color_type)) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Invalid pixel format");
@@ -184,7 +186,7 @@ String VideoFrame::format() const {
switch (local_frame->format()) {
case media::PIXEL_FORMAT_I420:
- return "I420";
+ return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kI420);
default:
NOTREACHED();
@@ -343,8 +345,9 @@ ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
if ((local_frame->IsMappable() || local_frame->HasTextures()) &&
(local_frame->format() == media::PIXEL_FORMAT_I420 ||
- (local_frame->format() == media::PIXEL_FORMAT_NV12 &&
- local_frame->HasTextures()))) {
+ (local_frame->HasTextures() &&
+ (local_frame->format() == media::PIXEL_FORMAT_NV12 ||
+ local_frame->format() == media::PIXEL_FORMAT_ABGR)))) {
scoped_refptr<StaticBitmapImage> image;
gfx::ColorSpace gfx_color_space = local_frame->ColorSpace();
gfx_color_space = gfx_color_space.GetWithMatrixAndRange(
@@ -376,6 +379,8 @@ ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
} else {
viz::RasterContextProvider* raster_context_provider =
Platform::Current()->SharedMainThreadContextProvider();
+ auto* ri = raster_context_provider->RasterInterface();
+
gpu::SharedImageInterface* shared_image_interface =
raster_context_provider->SharedImageInterface();
uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2;
@@ -393,23 +398,24 @@ ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
dest_holder.sync_token = shared_image_interface->GenUnverifiedSyncToken();
dest_holder.texture_target = GL_TEXTURE_2D;
- media::ConvertFromVideoFrameYUV(local_frame.get(),
- raster_context_provider, dest_holder);
+ if (local_frame->NumTextures() == 1) {
+ ri->WaitSyncTokenCHROMIUM(dest_holder.sync_token.GetConstData());
+ ri->CopySubTexture(
+ local_frame->mailbox_holder(0).mailbox, dest_holder.mailbox,
+ GL_TEXTURE_2D, 0, 0, 0, 0, local_frame->coded_size().width(),
+ local_frame->coded_size().height(), GL_FALSE, GL_FALSE);
+ } else {
+ media::VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching(
+ local_frame.get(), raster_context_provider, dest_holder);
+ }
gpu::SyncToken sync_token;
- raster_context_provider->RasterInterface()
- ->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+ ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
- [](viz::RasterContextProvider* context, gpu::Mailbox mailbox,
- const gpu::SyncToken& sync_token, bool is_lost) {
- auto* ri = context->RasterInterface();
- auto* sii = context->SharedImageInterface();
- ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- gpu::SyncToken ri_sync_token;
- ri->GenUnverifiedSyncTokenCHROMIUM(ri_sync_token.GetData());
- sii->DestroySharedImage(ri_sync_token, mailbox);
- },
- base::Unretained(raster_context_provider), dest_holder.mailbox));
+ [](gpu::SharedImageInterface* sii, gpu::Mailbox mailbox,
+ const gpu::SyncToken& sync_token,
+ bool is_lost) { sii->DestroySharedImage(sync_token, mailbox); },
+ base::Unretained(shared_image_interface), dest_holder.mailbox));
const SkImageInfo sk_image_info =
SkImageInfo::Make(codedWidth(), codedHeight(), kN32_SkColorType,
@@ -421,6 +427,13 @@ ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
SharedGpuContext::ContextProviderWrapper(),
base::PlatformThread::CurrentRef(),
Thread::Current()->GetTaskRunner(), std::move(release_callback));
+
+ if (local_frame->HasTextures()) {
+ // Attach a new sync token to |local_frame|, so it's not destroyed
+ // before |image| is fully created.
+ media::WaitAndReplaceSyncTokenClient client(ri);
+ local_frame->UpdateReleaseSyncToken(&client);
+ }
}
ImageBitmap* image_bitmap =
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl
index 66dc3717e9d..028602b1d4d 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_frame.idl
@@ -4,11 +4,6 @@
// https://github.com/WICG/web-codecs
-enum VideoPixelFormat {
- // 4:2:0 subsampled planar YUV
- "I420"
-};
-
[
Exposed=(Window,Worker),
Serializable,
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl b/chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl
new file mode 100644
index 00000000000..490e6fa4c7d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl
@@ -0,0 +1,10 @@
+// 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://github.com/WICG/web-codecs
+
+enum VideoPixelFormat {
+ // 4:2:0 subsampled planar YUV
+ "I420"
+};
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database.idl b/chromium/third_party/blink/renderer/modules/webdatabase/database.idl
index b9a96a6ccbc..15ceea75811 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database.idl
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database.idl
@@ -28,7 +28,7 @@
// https://www.w3.org/TR/webdatabase/#database
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface Database {
readonly attribute DOMString version;
// TODO(crbug.com/841185): |callback|, |errorCallback|, and
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc
index 3b2f6b844da..fc82b0db66f 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc
@@ -60,8 +60,10 @@ const char DatabaseClient::kSupplementName[] = "DatabaseClient";
bool DatabaseClient::AllowDatabase(ExecutionContext* context) {
DCHECK(context->IsContextThread());
LocalDOMWindow* window = To<LocalDOMWindow>(context);
- if (auto* client = window->GetFrame()->GetContentSettingsClient())
- return client->AllowDatabase();
+ if (auto* client = window->GetFrame()->GetContentSettingsClient()) {
+ return client->AllowStorageAccessSync(
+ WebContentSettingsClient::StorageType::kDatabase);
+ }
return true;
}
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_error.idl b/chromium/third_party/blink/renderer/modules/webdatabase/sql_error.idl
index 287ddad6818..c5a94690e48 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_error.idl
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_error.idl
@@ -28,7 +28,7 @@
// https://www.w3.org/TR/webdatabase/#sqlerror
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SQLError {
readonly attribute unsigned long code;
readonly attribute DOMString message;
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set.idl b/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set.idl
index acc7eda8d83..c90e8470f24 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set.idl
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set.idl
@@ -28,7 +28,7 @@
// https://www.w3.org/TR/webdatabase/#sqlresultset
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SQLResultSet {
readonly attribute SQLResultSetRowList rows;
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.idl b/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.idl
index 2f7b32e09ac..eefaedd2284 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.idl
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.idl
@@ -28,7 +28,7 @@
// https://www.w3.org/TR/webdatabase/#sqlresultsetrowlist
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SQLResultSetRowList {
readonly attribute unsigned long length;
[RaisesException, CallWith=ScriptState] getter any item(unsigned long index);
diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.idl b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.idl
index 01ca792addd..c80b21c781d 100644
--- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.idl
+++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction.idl
@@ -31,7 +31,7 @@ typedef sequence<any> ObjectArray;
// https://www.w3.org/TR/webdatabase/#sqltransaction
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface SQLTransaction {
// The spec defines |arguments| to be an "optional ObjectArray" though it defines the
// behavior when null is being passed.
diff --git a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
index 85f5e404765..8508f768494 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn
@@ -171,4 +171,8 @@ blink_modules_sources("webgl") {
# the implementation depends on a fair chunk of core/ --
# include the core pch for faster Windows compilation times.
configs += [ "//third_party/blink/renderer/core:blink_core_pch" ]
+
+ public_deps = [ "//device/vr/public/mojom:mojom_blink" ]
+ deps = [ "//third_party/blink/renderer/modules/xr:xr" ]
+ allow_circular_includes_from = deps
}
diff --git a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.idl b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.idl
index d174853f3a2..49611384219 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/angle_instanced_arrays.idl
@@ -32,7 +32,7 @@
[
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface ANGLEInstancedArrays {
const unsigned long VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_blend_min_max.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_blend_min_max.idl
index 4fb1be8d0fa..ce4cbaa419c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_blend_min_max.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_blend_min_max.idl
@@ -6,7 +6,7 @@
[
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTBlendMinMax {
const unsigned long MIN_EXT = 0x8007;
const unsigned long MAX_EXT = 0x8008;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_float.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_float.idl
index 2f4812a8021..162422d024a 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_float.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_float.idl
@@ -5,6 +5,6 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTColorBufferFloat {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.cc b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.cc
index 6581e588127..07dde691d60 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.cc
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.cc
@@ -29,7 +29,10 @@ namespace blink {
EXTColorBufferHalfFloat::EXTColorBufferHalfFloat(
WebGLRenderingContextBase* context)
- : WebGLExtension(context) {}
+ : WebGLExtension(context) {
+ context->ExtensionsUtil()->EnsureExtensionEnabled(
+ "GL_EXT_color_buffer_half_float");
+}
WebGLExtensionName EXTColorBufferHalfFloat::GetName() const {
return kEXTColorBufferHalfFloatName;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.idl
index 59a373fc034..39809daa1f7 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.idl
@@ -26,6 +26,10 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_half_float
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTColorBufferHalfFloat {
+ const GLenum RGBA16F_EXT = 0x881A;
+ const GLenum RGB16F_EXT = 0x881B;
+ const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
+ const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.idl
index cbbe4712f73..35d679a3f29 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.idl
@@ -8,7 +8,7 @@ typedef unsigned long long GLuint64EXT;
[
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTDisjointTimerQuery {
const GLenum QUERY_COUNTER_BITS_EXT = 0x8864;
const GLenum CURRENT_QUERY_EXT = 0x8865;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.idl
index e8110a164c4..cc05ad99560 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.idl
@@ -6,7 +6,7 @@
[
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTDisjointTimerQueryWebGL2 {
const GLenum QUERY_COUNTER_BITS_EXT = 0x8864;
const GLenum TIME_ELAPSED_EXT = 0x88BF;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_float_blend.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_float_blend.idl
index 7008ab17b9a..199d5649c3d 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_float_blend.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_float_blend.idl
@@ -5,6 +5,6 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_float_blend/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTFloatBlend {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_frag_depth.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_frag_depth.idl
index 7c64090d029..f5d7000e47d 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_frag_depth.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_frag_depth.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_frag_depth/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTFragDepth {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.idl
index f57440d7fac..57c9dce5592 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.idl
@@ -5,6 +5,6 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_shader_texture_lod/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface EXTShaderTextureLOD {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_srgb.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_srgb.idl
index 327d5da3c6a..b12215235f2 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_srgb.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_srgb.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface EXTsRGB {
const unsigned long SRGB_EXT = 0x8C40;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.idl
index 1de39693cde..1edff3cea2b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_bptc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface EXTTextureCompressionBPTC {
const unsigned long COMPRESSED_RGBA_BPTC_UNORM_EXT = 0x8E8C;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_rgtc.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_rgtc.idl
index f2762fab545..f790eb3f88f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_rgtc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_compression_rgtc.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_rgtc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface EXTTextureCompressionRGTC {
const unsigned long COMPRESSED_RED_RGTC1_EXT = 0x8DBB;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.idl
index b582bf5463c..24752b17128 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface EXTTextureFilterAnisotropic {
const unsigned long TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_norm_16.idl b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_norm_16.idl
index 38158d129bb..f79de39bb6e 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ext_texture_norm_16.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ext_texture_norm_16.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_texture_norm16/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface EXTTextureNorm16 {
const unsigned long R16_EXT = 0x822A;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl
index 658af3f82e0..68f5491fb27 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface KHRParallelShaderCompile {
const GLenum COMPLETION_STATUS_KHR = 0x91B1;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_draw_buffers_indexed.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_draw_buffers_indexed.idl
index 84ed0781c10..aa480aa3046 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_draw_buffers_indexed.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_draw_buffers_indexed.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/OES_draw_buffers_indexed/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface OESDrawBuffersIndexed {
void enableiOES(GLenum target, GLuint index);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_element_index_uint.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_element_index_uint.idl
index 1d01d62c62a..5d57a3024a6 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_element_index_uint.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_element_index_uint.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESElementIndexUint {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_fbo_render_mipmap.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_fbo_render_mipmap.idl
index eb6abac0ae1..efd96159f47 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_fbo_render_mipmap.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_fbo_render_mipmap.idl
@@ -5,6 +5,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_fbo_render_mipmap/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESFboRenderMipmap {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_standard_derivatives.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_standard_derivatives.idl
index 83a09f733db..6df7f72517c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_standard_derivatives.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_standard_derivatives.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface OESStandardDerivatives {
const unsigned long FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float.idl
index 4a0fda07fa7..016920383f7 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_texture_float/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESTextureFloat {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float_linear.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float_linear.idl
index c3e048fda50..4a0f072ad2c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float_linear.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_float_linear.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESTextureFloatLinear {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float.idl
index d2e6d13a099..c397ca4017b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface OESTextureHalfFloat {
const GLenum HALF_FLOAT_OES = 0x8D61;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.idl b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.idl
index e9917614e26..0be0e6f7706 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float_linear/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESTextureHalfFloatLinear {
};
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 7f78d15ebc3..5352538cf31 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
@@ -27,7 +27,7 @@
[
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface OESVertexArrayObject {
const unsigned long VERTEX_ARRAY_BINDING_OES = 0x85B5;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl b/chromium/third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl
index b004ba1a70a..b93d7780d26 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/OVR_multiview2/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
]
interface OVRMultiview2 {
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 6a67432760a..8aefd1415b6 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
@@ -15,6 +15,7 @@
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/modules/webgl/ext_color_buffer_float.h"
+#include "third_party/blink/renderer/modules/webgl/ext_color_buffer_half_float.h"
#include "third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.h"
#include "third_party/blink/renderer/modules/webgl/ext_float_blend.h"
#include "third_party/blink/renderer/modules/webgl/ext_texture_compression_bptc.h"
@@ -71,15 +72,31 @@ static bool ShouldCreateContext(WebGraphicsContext3DProvider* context_provider,
CanvasRenderingContext* WebGL2RenderingContext::Factory::Create(
CanvasRenderingContextHost* host,
const CanvasContextCreationAttributesCore& attrs) {
+ // Create a copy of attrs so flags can be modified if needed before passing
+ // into the WebGL2RenderingContext constructor.
+ CanvasContextCreationAttributesCore attribs = attrs;
+
+ // The xr_compatible attribute needs to be handled before creating the context
+ // because the GPU process may potentially be restarted in order to be XR
+ // compatible. This scenario occurs if the GPU process is not using the GPU
+ // that the VR headset is plugged into. If the GPU process is restarted, the
+ // WebGraphicsContext3DProvider must be created using the new one.
+ if (attribs.xr_compatible &&
+ !WebGLRenderingContextBase::MakeXrCompatibleSync(host)) {
+ // If xr compatibility is requested and we can't be xr compatible, return a
+ // context with the flag set to false.
+ attribs.xr_compatible = false;
+ }
+
bool using_gpu_compositing;
std::unique_ptr<WebGraphicsContext3DProvider> context_provider(
CreateWebGraphicsContext3DProvider(
- host, attrs, Platform::kWebGL2ContextType, &using_gpu_compositing));
+ host, attribs, Platform::kWebGL2ContextType, &using_gpu_compositing));
if (!ShouldCreateContext(context_provider.get(), host))
return nullptr;
WebGL2RenderingContext* rendering_context =
MakeGarbageCollected<WebGL2RenderingContext>(
- host, std::move(context_provider), using_gpu_compositing, attrs);
+ host, std::move(context_provider), using_gpu_compositing, attribs);
if (!rendering_context->GetDrawingBuffer()) {
host->HostDispatchEvent(
@@ -129,12 +146,13 @@ ImageBitmap* WebGL2RenderingContext::TransferToImageBitmap(
void WebGL2RenderingContext::RegisterContextExtensions() {
// Register extensions.
RegisterExtension(ext_color_buffer_float_);
+ RegisterExtension(ext_color_buffer_half_float_);
RegisterExtension(ext_disjoint_timer_query_web_gl2_);
RegisterExtension(ext_float_blend_);
RegisterExtension(ext_texture_compression_bptc_);
RegisterExtension(ext_texture_compression_rgtc_);
RegisterExtension(ext_texture_filter_anisotropic_);
- RegisterExtension(ext_texture_norm16_, kDraftExtension);
+ RegisterExtension(ext_texture_norm16_);
RegisterExtension(khr_parallel_shader_compile_);
RegisterExtension(oes_draw_buffers_indexed_, kDraftExtension);
RegisterExtension(oes_texture_float_linear_);
@@ -158,6 +176,7 @@ void WebGL2RenderingContext::RegisterContextExtensions() {
void WebGL2RenderingContext::Trace(Visitor* visitor) const {
visitor->Trace(ext_color_buffer_float_);
+ visitor->Trace(ext_color_buffer_half_float_);
visitor->Trace(ext_disjoint_timer_query_web_gl2_);
visitor->Trace(ext_float_blend_);
visitor->Trace(ext_texture_compression_bptc_);
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 087ee21eb12..c325a8dc62e 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
@@ -15,6 +15,7 @@ namespace blink {
class CanvasContextCreationAttributesCore;
class EXTColorBufferFloat;
+class EXTColorBufferHalfFloat;
class EXTFloatBlend;
class EXTTextureCompressionBPTC;
class EXTTextureCompressionRGTC;
@@ -71,6 +72,7 @@ class WebGL2RenderingContext : public WebGL2RenderingContextBase {
protected:
Member<EXTColorBufferFloat> ext_color_buffer_float_;
+ Member<EXTColorBufferHalfFloat> ext_color_buffer_half_float_;
Member<EXTDisjointTimerQueryWebGL2> ext_disjoint_timer_query_web_gl2_;
Member<EXTFloatBlend> ext_float_blend_;
Member<EXTTextureCompressionBPTC> ext_texture_compression_bptc_;
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 2d8068bf9f2..9d96ae4f9c6 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
@@ -542,6 +542,15 @@ ScriptValue WebGL2RenderingContextBase::getInternalformatParameter(
case GL_R16F:
case GL_RG16F:
case GL_RGBA16F:
+ if (!ExtensionEnabled(kEXTColorBufferFloatName) &&
+ !ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+ SynthesizeGLError(
+ GL_INVALID_ENUM, "getInternalformatParameter",
+ "invalid internalformat when EXT_color_buffer_[half_]float "
+ "is not enabled");
+ return ScriptValue::CreateNull(script_state->GetIsolate());
+ }
+ break;
case GL_R32F:
case GL_RG32F:
case GL_RGBA32F:
@@ -905,6 +914,16 @@ void WebGL2RenderingContextBase::RenderbufferStorageImpl(
case GL_R16F:
case GL_RG16F:
case GL_RGBA16F:
+ if (!ExtensionEnabled(kEXTColorBufferFloatName) &&
+ !ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+ SynthesizeGLError(
+ GL_INVALID_ENUM, function_name,
+ "EXT_color_buffer_float/EXT_color_buffer_half_float not enabled");
+ return;
+ }
+ RenderbufferStorageHelper(target, samples, internalformat, width, height,
+ function_name);
+ break;
case GL_R32F:
case GL_RG32F:
case GL_RGBA32F:
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_color_buffer_float.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_color_buffer_float.idl
index d489a779745..08e14545aa0 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_color_buffer_float.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_color_buffer_float.idl
@@ -26,6 +26,9 @@
// https://www.khronos.org/registry/webgl/extensions/WebGL_color_buffer_float/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLColorBufferFloat {
+ const GLenum RGBA32F_EXT = 0x8814;
+ const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
+ const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl
index a4d521d87fd..916dc2677ef 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTextureASTC {
/* Compressed Texture Formats */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.idl
index ccfcee9e288..40c787a9979 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTextureETC {
/* Compressed Texture Format */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.idl
index d21cccddfec..4e605d5e0dd 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTextureETC1 {
/* Compressed Texture Formats */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.idl
index 7d126be2dc0..b0601d128c0 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTexturePVRTC {
/* Compressed Texture Formats */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.idl
index 6381d2c3cca..514935628da 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTextureS3TC {
/* Compressed Texture Formats */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.idl
index 1972a023aa5..fa56ad2d24c 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.idl
@@ -5,7 +5,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLCompressedTextureS3TCsRGB {
/* Compressed Texture Formats */
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.idl
index 14807edb2b6..a1db3fcd84b 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLDebugRendererInfo {
const unsigned long UNMASKED_VENDOR_WEBGL = 0x9245;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_shaders.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_shaders.idl
index dbb4e8de446..2a8d08dafe9 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_shaders.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_debug_shaders.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_debug_shaders/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLDebugShaders {
DOMString? getTranslatedShaderSource(WebGLShader shader);
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_depth_texture.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_depth_texture.idl
index 6bbcc0ea894..6142c1c447a 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_depth_texture.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_depth_texture.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLDepthTexture {
const unsigned long UNSIGNED_INT_24_8_WEBGL = 0x84FA;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_buffers.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_buffers.idl
index cc371209614..f89f4a5f30f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_buffers.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_buffers.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_buffers/
[
- NoInterfaceObject,
+ LegacyNoInterfaceObject,
DoNotCheckConstants
] interface WebGLDrawBuffers {
const GLenum COLOR_ATTACHMENT0_WEBGL = 0x8CE0;
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.idl
index 26c99e11815..0b587d1d51f 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_draw_instanced_base_vertex_base_instance.idl
@@ -4,7 +4,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_instanced_base_vertex_base_instance/
-[NoInterfaceObject]
+[LegacyNoInterfaceObject]
interface WebGLDrawInstancedBaseVertexBaseInstance {
void drawArraysInstancedBaseInstanceWEBGL(
GLenum mode,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_lose_context.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_lose_context.idl
index 1c38b97e903..201f0bd955e 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_lose_context.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_lose_context.idl
@@ -26,7 +26,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_lose_context/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLLoseContext {
void loseContext();
void restoreContext();
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
index 383b5e0db65..138db35c3c8 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw.idl
@@ -4,7 +4,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_multi_draw/
-[NoInterfaceObject]
+[LegacyNoInterfaceObject]
interface WebGLMultiDraw {
void multiDrawArraysWEBGL(GLenum mode,
(Int32Array or sequence<long>) firstsList,
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
index c29508ab63b..c9b40ecb181 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idl
@@ -4,7 +4,7 @@
// https://www.khronos.org/registry/webgl/extensions/WEBGL_multi_draw_instanced_base_vertex_base_instance/
-[NoInterfaceObject]
+[LegacyNoInterfaceObject]
interface WebGLMultiDrawInstancedBaseVertexBaseInstance {
void multiDrawArraysInstancedBaseInstanceWEBGL(
GLenum mode,
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 f7874b0f694..30460118bfe 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
@@ -38,7 +38,7 @@
#include "gpu/config/gpu_feature_info.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
-#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/gpu/gpu.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
@@ -116,6 +116,7 @@
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -779,15 +780,16 @@ scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage() {
auto color_params = ColorParams();
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
- size, SharedGpuContext::ContextProviderWrapper(),
- GetDrawingBuffer()->FilterQuality(), color_params,
- is_origin_top_left_, RasterMode::kGPU,
- 0u /*shared_image_usage_flags*/);
+ size, GetDrawingBuffer()->FilterQuality(), color_params,
+ CanvasResourceProvider::ShouldInitialize::kNo,
+ SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
+ is_origin_top_left_, 0u /*shared_image_usage_flags*/);
// todo(bug 1090962) This CPU fallback is needed as it would break
// webgl_conformance_gles_passthrough_tests on Android FYI for Nexus 5x.
if (!resource_provider || !resource_provider->IsValid()) {
resource_provider = CanvasResourceProvider::CreateBitmapProvider(
- size, GetDrawingBuffer()->FilterQuality(), color_params);
+ size, GetDrawingBuffer()->FilterQuality(), color_params,
+ CanvasResourceProvider::ShouldInitialize::kNo);
}
if (!resource_provider || !resource_provider->IsValid())
@@ -817,7 +819,7 @@ ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
if (xr_compatible_)
return ScriptPromise::CastUndefined(script_state);
- if (!base::FeatureList::IsEnabled(features::kWebXrMultiGpu)) {
+ if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled()) {
xr_compatible_ = true;
return ScriptPromise::CastUndefined(script_state);
}
@@ -857,11 +859,11 @@ bool WebGLRenderingContextBase::DidGpuRestart(
bool WebGLRenderingContextBase::MakeXrCompatibleSync(
CanvasRenderingContextHost* host) {
- if (!base::FeatureList::IsEnabled(features::kWebXrMultiGpu))
+ if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled())
return true;
device::mojom::blink::XrCompatibleResult xr_compatible_result =
- device::mojom::blink::XrCompatibleResult::kNotCompatible;
+ device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable;
HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(host);
NavigatorXR* navigator_xr = NavigatorXR::From(canvas->GetDocument());
if (navigator_xr)
@@ -873,14 +875,14 @@ bool WebGLRenderingContextBase::MakeXrCompatibleSync(
void WebGLRenderingContextBase::MakeXrCompatibleAsync() {
if (!canvas()) {
xr_compatible_ = false;
- CompleteXrCompatiblePromiseIfPending();
+ CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
return;
}
NavigatorXR* navigator_xr = NavigatorXR::From(canvas()->GetDocument());
if (!navigator_xr) {
xr_compatible_ = false;
- CompleteXrCompatiblePromiseIfPending();
+ CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
return;
}
@@ -894,19 +896,39 @@ void WebGLRenderingContextBase::OnMakeXrCompatibleFinished(
device::mojom::blink::XrCompatibleResult xr_compatible_result) {
xr_compatible_ = IsXrCompatibleFromResult(xr_compatible_result);
- // If the gpu is restarted, MaybeRestoreContext will resolve the promise on
- // the subsequent restore.
- if (!DidGpuRestart(xr_compatible_result))
- CompleteXrCompatiblePromiseIfPending();
+ // If the gpu process is restarted, MaybeRestoreContext will resolve the
+ // promise on the subsequent restore.
+ if (!DidGpuRestart(xr_compatible_result)) {
+ DOMExceptionCode exception_code = DOMExceptionCode::kUnknownError;
+ switch (xr_compatible_result) {
+ case device::mojom::blink::XrCompatibleResult::kAlreadyCompatible:
+ exception_code = DOMExceptionCode::kNoError;
+ break;
+ case device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable:
+ // Per WebXR spec, reject with an InvalidStateError if device is null.
+ exception_code = DOMExceptionCode::kInvalidStateError;
+ break;
+ case device::mojom::blink::XrCompatibleResult::kWebXrFeaturePolicyBlocked:
+ exception_code = DOMExceptionCode::kSecurityError;
+ break;
+ case device::mojom::blink::XrCompatibleResult::kCompatibleAfterRestart:
+ case device::mojom::blink::XrCompatibleResult::kNotCompatibleAfterRestart:
+ NOTREACHED();
+ }
+ CompleteXrCompatiblePromiseIfPending(exception_code);
+ }
}
-void WebGLRenderingContextBase::CompleteXrCompatiblePromiseIfPending() {
+void WebGLRenderingContextBase::CompleteXrCompatiblePromiseIfPending(
+ DOMExceptionCode exception_code) {
if (make_xr_compatible_resolver_) {
if (xr_compatible_) {
+ DCHECK(exception_code == DOMExceptionCode::kNoError);
make_xr_compatible_resolver_->Resolve();
} else {
+ DCHECK(exception_code != DOMExceptionCode::kNoError);
make_xr_compatible_resolver_->Reject(
- MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError));
+ MakeGarbageCollected<DOMException>(exception_code));
}
make_xr_compatible_resolver_ = nullptr;
@@ -985,6 +1007,14 @@ static const GLenum kSupportedInternalFormatsCopyTexImageFloatES3[] = {
GL_R16F, GL_R32F, GL_RG16F, GL_RG32F, GL_RGB16F,
GL_RGB32F, GL_RGBA16F, GL_RGBA32F, GL_R11F_G11F_B10F};
+// Exposed by EXT_color_buffer_half_float
+static const GLenum kSupportedInternalFormatsCopyTexImageHalfFloatES3[] = {
+ GL_R16F,
+ GL_RG16F,
+ GL_RGB16F,
+ GL_RGBA16F,
+};
+
// ES3 enums supported by TexImageSource
static const GLenum kSupportedInternalFormatsTexImageSourceES3[] = {
GL_R8, GL_R16F, GL_R32F, GL_R8UI, GL_RG8,
@@ -1342,6 +1372,7 @@ void WebGLRenderingContextBase::InitializeNewContext() {
is_web_gl_depth_texture_formats_types_added_ = false;
is_ext_srgb_formats_types_added_ = false;
is_ext_color_buffer_float_formats_added_ = false;
+ is_ext_color_buffer_half_float_formats_added_ = false;
is_ext_texture_norm16_added_ = false;
supported_internal_formats_.clear();
@@ -2352,6 +2383,12 @@ bool WebGLRenderingContextBase::ValidateCopyTexFormat(const char* function_name,
kSupportedInternalFormatsCopyTexImageFloatES3);
is_ext_color_buffer_float_formats_added_ = true;
}
+ if (!is_ext_color_buffer_half_float_formats_added_ &&
+ ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+ ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
+ kSupportedInternalFormatsCopyTexImageHalfFloatES3);
+ is_ext_color_buffer_half_float_formats_added_ = true;
+ }
if (supported_internal_formats_copy_tex_image_.find(internalformat) ==
supported_internal_formats_copy_tex_image_.end()) {
@@ -3242,6 +3279,95 @@ ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter(
}
}
+namespace {
+
+// WebGL parameters which can be used to identify users.
+// These parameters should each be uniquely defined,
+// see third_party/khronos/GLES2/gl2.h for their definitions.
+static const GLenum kIdentifiableGLParams[] = {
+ // getParameter()
+ GL_ALIASED_LINE_WIDTH_RANGE, // GetWebGLFloatArrayParameter
+ GL_ALIASED_POINT_SIZE_RANGE, // GetWebGLFloatArrayParameter
+ GL_ALPHA_BITS, // GetIntParameter
+ GL_BLUE_BITS, // GetIntParameter
+ GL_DEPTH_BITS, // GetIntParameter
+ GL_GREEN_BITS, // GetIntParameter
+ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, // GetIntParameter
+ GL_MAX_CUBE_MAP_TEXTURE_SIZE, // GetIntParameter
+ GL_MAX_FRAGMENT_UNIFORM_VECTORS, // GetIntParameter
+ GL_MAX_RENDERBUFFER_SIZE, // GetIntParameter
+ GL_MAX_TEXTURE_IMAGE_UNITS, // GetIntParameter
+ GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, // GetFloatParameter
+ GL_MAX_TEXTURE_SIZE, // GetIntParameter
+ GL_MAX_VARYING_VECTORS, // GetIntParameter
+ GL_MAX_VERTEX_ATTRIBS, // GetIntParameter
+ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, // GetIntParameter
+ GL_MAX_VERTEX_UNIFORM_VECTORS, // GetIntParameter
+ GL_MAX_VIEWPORT_DIMS, // GetWebGLIntArrayParameter
+ GL_RED_BITS, // GetIntParameter
+ GL_SHADING_LANGUAGE_VERSION,
+ GL_STENCIL_BITS, // GetIntParameter
+ GL_VERSION,
+ WebGLDebugRendererInfo::kUnmaskedRendererWebgl,
+ WebGLDebugRendererInfo::kUnmaskedVendorWebgl,
+
+ // getRenderBufferParameter()
+ GL_RENDERBUFFER_GREEN_SIZE,
+ GL_RENDERBUFFER_BLUE_SIZE,
+ GL_RENDERBUFFER_RED_SIZE,
+ GL_RENDERBUFFER_ALPHA_SIZE,
+ GL_RENDERBUFFER_DEPTH_SIZE,
+ GL_RENDERBUFFER_STENCIL_SIZE,
+ GL_RENDERBUFFER_SAMPLES,
+};
+
+bool ShouldMeasureGLParam(GLenum pname) {
+ return IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter) &&
+ std::find(std::begin(kIdentifiableGLParams),
+ std::end(kIdentifiableGLParams),
+ pname) != std::end(kIdentifiableGLParams);
+}
+
+} // namespace
+
+void WebGLRenderingContextBase::RecordIdentifiableGLParameterDigest(
+ GLenum pname,
+ IdentifiableToken value) {
+ DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+ blink::IdentifiableSurface::Type::kWebGLParameter));
+ const auto ukm_params = GetUkmParameters();
+ blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
+ .Set(blink::IdentifiableSurface::FromTypeAndToken(
+ blink::IdentifiableSurface::Type::kWebGLParameter, pname),
+ value)
+ .Record(ukm_params.ukm_recorder);
+}
+
+void WebGLRenderingContextBase::RecordShaderPrecisionFormatForStudy(
+ GLenum shader_type,
+ GLenum precision_type,
+ WebGLShaderPrecisionFormat* format) {
+ DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+ blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat));
+
+ const auto& ukm_params = GetUkmParameters();
+ IdentifiableTokenBuilder builder;
+ auto surface_token =
+ builder.AddValue(shader_type).AddValue(precision_type).GetToken();
+ auto sample_token = builder.AddValue(format->rangeMin())
+ .AddValue(format->rangeMax())
+ .AddValue(format->precision())
+ .GetToken();
+
+ blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
+ .Set(blink::IdentifiableSurface::FromTypeAndToken(
+ blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat,
+ surface_token),
+ sample_token)
+ .Record(ukm_params.ukm_recorder);
+}
+
ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
GLenum pname) {
if (isContextLost())
@@ -3381,6 +3507,12 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
case GL_SCISSOR_TEST:
return GetBooleanParameter(script_state, pname);
case GL_SHADING_LANGUAGE_VERSION:
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(
+ pname, IdentifiabilityBenignStringToken(String(
+ ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION))));
+ }
return WebGLAny(
script_state,
"WebGL GLSL ES 1.0 (" +
@@ -3443,6 +3575,12 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
case GL_VENDOR:
return WebGLAny(script_state, String("WebKit"));
case GL_VERSION:
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(
+ pname, IdentifiabilityBenignStringToken(
+ String(ContextGL()->GetString(GL_VERSION))));
+ }
return WebGLAny(
script_state,
"WebGL 1.0 (" + String(ContextGL()->GetString(GL_VERSION)) + ")");
@@ -3457,17 +3595,31 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
"invalid parameter name, OES_standard_derivatives not enabled");
return ScriptValue::CreateNull(script_state->GetIsolate());
case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
- if (ExtensionEnabled(kWebGLDebugRendererInfoName))
+ if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(
+ pname, IdentifiabilityBenignStringToken(
+ String(ContextGL()->GetString(GL_RENDERER))));
+ }
return WebGLAny(script_state,
String(ContextGL()->GetString(GL_RENDERER)));
+ }
SynthesizeGLError(
GL_INVALID_ENUM, "getParameter",
"invalid parameter name, WEBGL_debug_renderer_info not enabled");
return ScriptValue::CreateNull(script_state->GetIsolate());
case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
- if (ExtensionEnabled(kWebGLDebugRendererInfoName))
+ if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(
+ pname, IdentifiabilityBenignStringToken(
+ String(ContextGL()->GetString(GL_VENDOR))));
+ }
return WebGLAny(script_state,
String(ContextGL()->GetString(GL_VENDOR)));
+ }
SynthesizeGLError(
GL_INVALID_ENUM, "getParameter",
"invalid parameter name, WEBGL_debug_renderer_info not enabled");
@@ -3644,10 +3796,12 @@ ScriptValue WebGLRenderingContextBase::getRenderbufferParameter(
case GL_RENDERBUFFER_BLUE_SIZE:
case GL_RENDERBUFFER_ALPHA_SIZE:
case GL_RENDERBUFFER_DEPTH_SIZE:
- ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
- return WebGLAny(script_state, value);
case GL_RENDERBUFFER_STENCIL_SIZE:
ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(pname, value);
+ }
return WebGLAny(script_state, value);
case GL_RENDERBUFFER_INTERNAL_FORMAT:
return WebGLAny(script_state, renderbuffer_binding_->InternalFormat());
@@ -3723,8 +3877,13 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat(
GLint precision = 0;
ContextGL()->GetShaderPrecisionFormat(shader_type, precision_type, range,
&precision);
- return MakeGarbageCollected<WebGLShaderPrecisionFormat>(range[0], range[1],
- precision);
+ auto* result = MakeGarbageCollected<WebGLShaderPrecisionFormat>(
+ range[0], range[1], precision);
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat)) {
+ RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
+ }
+ return result;
}
String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) {
@@ -4508,16 +4667,15 @@ void WebGLRenderingContextBase::readPixels(
GLenum format,
GLenum type,
MaybeShared<DOMArrayBufferView> pixels) {
- if (IsUserInIdentifiabilityStudy()) {
- base::Optional<UkmParameters> ukm_params = ukm_parameters();
- if (ukm_params) {
- blink::IdentifiabilityMetricBuilder(ukm_params->source_id)
- .Set(blink::IdentifiableSurface::FromTypeAndInput(
- blink::IdentifiableSurface::Type::kCanvasReadback,
- GetContextType()),
- 0)
- .Record(ukm_params->ukm_recorder);
- }
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kCanvasReadback)) {
+ const auto& ukm_params = GetUkmParameters();
+ blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
+ .Set(blink::IdentifiableSurface::FromTypeAndToken(
+ blink::IdentifiableSurface::Type::kCanvasReadback,
+ GetContextType()),
+ 0)
+ .Record(ukm_params.ukm_recorder);
}
ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), 0);
}
@@ -5192,11 +5350,13 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
if (isContextLost())
return;
DCHECK(pixels);
- if (pixels->data()->BufferBase()->IsDetached()) {
+ DCHECK(!pixels->data().IsNull());
+ if (pixels->BufferBase()->IsDetached()) {
SynthesizeGLError(GL_INVALID_VALUE, func_name,
"The source data has been detached.");
return;
}
+
if (!ValidateTexImageBinding(func_name, function_id, target))
return;
TexImageFunctionType function_type;
@@ -5222,6 +5382,8 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
adjusted_source_image_rect.MaxY());
}
+ // TODO(crbug.com/1115317): Should be compatible with uint_8, float16 and
+ // float32.
Vector<uint8_t> data;
bool need_conversion = true;
// The data from ImageData is always of format RGBA8.
@@ -5236,7 +5398,7 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
type = GL_FLOAT;
}
if (!WebGLImageConversion::ExtractImageData(
- pixels->data()->Data(),
+ pixels->data().GetAsUint8ClampedArray()->Data(),
WebGLImageConversion::DataFormat::kDataFormatRGBA8, pixels->Size(),
adjusted_source_image_rect, depth, unpack_image_height, format,
type, unpack_flip_y_, unpack_premultiply_alpha_, data)) {
@@ -5245,7 +5407,9 @@ void WebGLRenderingContextBase::TexImageHelperImageData(
}
}
ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
- const uint8_t* bytes = need_conversion ? data.data() : pixels->data()->Data();
+ const uint8_t* bytes = need_conversion
+ ? data.data()
+ : pixels->data().GetAsUint8ClampedArray()->Data();
if (function_id == kTexImage2D) {
DCHECK_EQ(unpack_image_height, 0);
TexImage2DBase(
@@ -5766,7 +5930,7 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
if (source_image_rect_is_default) {
// Try using optimized CPU-GPU path for some formats: e.g. Y16 and Y8. It
// leaves early for other formats or if frame is stored on GPU.
- ScopedUnpackParametersResetRestore(
+ ScopedUnpackParametersResetRestore unpack_params(
this, unpack_flip_y_ || unpack_premultiply_alpha_);
if (video->TexImageImpl(
static_cast<WebMediaPlayer::TexImageFunctionID>(function_id),
@@ -5886,7 +6050,7 @@ void WebGLRenderingContextBase::TexImageHelperImageBitmap(
}
// TODO(kbr): refactor this away to use TexImageImpl on image.
- sk_sp<SkImage> sk_image = paint_image.GetSkImage();
+ sk_sp<SkImage> sk_image = paint_image.GetSwSkImage();
if (!sk_image) {
SynthesizeGLError(GL_OUT_OF_MEMORY, func_name,
"ImageBitmap unexpectedly empty");
@@ -5896,9 +6060,9 @@ void WebGLRenderingContextBase::TexImageHelperImageBitmap(
SkPixmap pixmap;
uint8_t* pixel_data_ptr = nullptr;
Vector<uint8_t> pixel_data;
- // In the case where an ImageBitmap is not texture backed, peekPixels() always
- // succeed. However, when it is texture backed and !canUseTexImageByGPU, we
- // do a GPU read back.
+ // PaintImage::GetSwSkImage() can return a lazily generated image which will
+ // cause peekPixels() to fail. In that case we use CopyBitmapData to force
+ // image generation.
bool peek_succeed = sk_image->peekPixels(&pixmap);
if (peek_succeed) {
pixel_data_ptr = static_cast<uint8_t*>(pixmap.writable_addr());
@@ -7006,6 +7170,10 @@ ScriptValue WebGLRenderingContextBase::GetFloatParameter(
GLfloat value = 0;
if (!isContextLost())
ContextGL()->GetFloatv(pname, &value);
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(pname, value);
+ }
return WebGLAny(script_state, value);
}
@@ -7028,6 +7196,10 @@ ScriptValue WebGLRenderingContextBase::GetIntParameter(
break;
}
}
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(
+ blink::IdentifiableSurface::Type::kWebGLParameter)) {
+ RecordIdentifiableGLParameterDigest(pname, value);
+ }
return WebGLAny(script_state, value);
}
@@ -7069,6 +7241,13 @@ ScriptValue WebGLRenderingContextBase::GetWebGLFloatArrayParameter(
default:
NOTIMPLEMENTED();
}
+ if (ShouldMeasureGLParam(pname)) {
+ blink::IdentifiableTokenBuilder builder;
+ for (unsigned i = 0; i < length; i++) {
+ builder.AddValue(value[i]);
+ }
+ RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
+ }
return WebGLAny(script_state, DOMFloat32Array::Create(value, length));
}
@@ -7090,6 +7269,13 @@ ScriptValue WebGLRenderingContextBase::GetWebGLIntArrayParameter(
default:
NOTIMPLEMENTED();
}
+ if (ShouldMeasureGLParam(pname)) {
+ blink::IdentifiableTokenBuilder builder;
+ for (unsigned i = 0; i < length; i++) {
+ builder.AddValue(value[i]);
+ }
+ RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
+ }
return WebGLAny(script_state, DOMInt32Array::Create(value, length));
}
@@ -8121,7 +8307,7 @@ void WebGLRenderingContextBase::DispatchContextLostEvent(TimerBase*) {
// behavior wasn't prevented. CompleteXrCompatiblePromiseIfPending rejects
// the promise if xr_compatible_ is false, which was set at the beginning of
// this method.
- CompleteXrCompatiblePromiseIfPending();
+ CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
}
}
@@ -8219,7 +8405,11 @@ void WebGLRenderingContextBase::MaybeRestoreContext(TimerBase*) {
WebGLContextEvent::Create(event_type_names::kWebglcontextrestored, "");
Host()->HostDispatchEvent(event);
- CompleteXrCompatiblePromiseIfPending();
+ if (xr_compatible_) {
+ CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kNoError);
+ } else {
+ CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
+ }
}
String WebGLRenderingContextBase::EnsureNotNull(const String& text) const {
@@ -8249,8 +8439,9 @@ CanvasResourceProvider* WebGLRenderingContextBase::
// TODO(fserb): why is this a BITMAP?
std::unique_ptr<CanvasResourceProvider> temp(
CanvasResourceProvider::CreateBitmapProvider(
- size, kLow_SkFilterQuality,
- CanvasColorParams())); // TODO: should this use the canvas's
+ size, kLow_SkFilterQuality, CanvasColorParams(),
+ CanvasResourceProvider::ShouldInitialize::kNo)); // TODO: should this
+ // use the canvas's
if (!temp)
return nullptr;
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 e9c377bf67d..ae4d65ad8a2 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
@@ -140,8 +140,8 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
return static_cast<HTMLCanvasElement*>(Host());
}
- base::Optional<UkmParameters> ukm_parameters() const {
- return Host()->ukm_parameters();
+ const UkmParameters GetUkmParameters() const {
+ return Host()->GetUkmParameters();
}
virtual String ContextName() const = 0;
@@ -799,7 +799,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
void MakeXrCompatibleAsync();
void OnMakeXrCompatibleFinished(
device::mojom::blink::XrCompatibleResult xr_compatible_result);
- void CompleteXrCompatiblePromiseIfPending();
+ void CompleteXrCompatiblePromiseIfPending(DOMExceptionCode exception_code);
bool xr_compatible_;
Member<ScriptPromiseResolver> make_xr_compatible_resolver_;
@@ -1018,6 +1018,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
bool is_web_gl_depth_texture_formats_types_added_ = false;
bool is_ext_srgb_formats_types_added_ = false;
bool is_ext_color_buffer_float_formats_added_ = false;
+ bool is_ext_color_buffer_half_float_formats_added_ = false;
bool is_ext_texture_norm16_added_ = false;
GLenumHashSet supported_internal_formats_;
@@ -1787,6 +1788,13 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
WebGraphicsContext3DProvider* context_provider);
static unsigned CurrentMaxGLContexts();
+ void RecordIdentifiableGLParameterDigest(GLenum pname,
+ IdentifiableToken value);
+
+ void RecordShaderPrecisionFormatForStudy(GLenum shader_type,
+ GLenum precision_type,
+ WebGLShaderPrecisionFormat* format);
+
static bool webgl_context_limits_initialized_;
static unsigned max_active_webgl_contexts_;
static unsigned max_active_webgl_contexts_on_worker_;
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 88259a38569..437dd9308a6 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
@@ -523,8 +523,8 @@ interface mixin WebGLRenderingContextBase {
void detachShader(WebGLProgram program, WebGLShader shader);
void disable(GLenum cap);
void disableVertexAttribArray(GLuint index);
- void drawArrays(GLenum mode, GLint first, GLsizei count);
- void drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
+ [NoAllocDirectCall] void drawArrays(GLenum mode, GLint first, GLsizei count);
+ [NoAllocDirectCall] void drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
void enable(GLenum cap);
void enableVertexAttribArray(GLuint index);
@@ -563,7 +563,7 @@ interface mixin WebGLRenderingContextBase {
DOMString? getShaderSource(WebGLShader shader);
- [HighEntropy, Measure] sequence<DOMString>? getSupportedExtensions();
+ [HighEntropy=Direct, Measure] sequence<DOMString>? getSupportedExtensions();
[CallWith=ScriptState] any getTexParameter(GLenum target, GLenum pname);
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.idl
index f73eac5b95c..8d95743d3ba 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.idl
@@ -5,6 +5,6 @@
// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLTimerQueryEXT {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl
index fb85de4c1c7..e1d6730c561 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.idl
@@ -26,6 +26,6 @@
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
[
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLVertexArrayObjectOES {
};
diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.idl
index e53cac6b40a..fddd62916ab 100644
--- a/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.idl
+++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_video_texture.idl
@@ -7,7 +7,7 @@
[
RuntimeEnabled=WebGLDraftExtensions,
DoNotCheckConstants,
- NoInterfaceObject
+ LegacyNoInterfaceObject
] interface WebGLVideoTexture {
const GLenum TEXTURE_VIDEO_IMAGE = 0x9248;
const GLenum SAMPLER_VIDEO_IMAGE = 0x9249;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
index 5854ec223e0..1099c43665f 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -48,6 +48,8 @@ blink_modules_sources("webgpu") {
"gpu_pipeline_layout.h",
"gpu_programmable_pass_encoder.cc",
"gpu_programmable_pass_encoder.h",
+ "gpu_query_set.cc",
+ "gpu_query_set.h",
"gpu_queue.cc",
"gpu_queue.h",
"gpu_render_bundle.cc",
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 1ceb786751c..550a547d8a7 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -39,6 +39,9 @@ WGPUBindingType AsDawnEnum<WGPUBindingType>(const WTF::String& webgpu_enum) {
if (webgpu_enum == "sampled-texture") {
return WGPUBindingType_SampledTexture;
}
+ if (webgpu_enum == "multisampled-texture") {
+ return WGPUBindingType_MultisampledTexture;
+ }
if (webgpu_enum == "readonly-storage-texture") {
return WGPUBindingType_ReadonlyStorageTexture;
}
@@ -97,6 +100,43 @@ WGPUCompareFunction AsDawnEnum<WGPUCompareFunction>(
}
template <>
+WGPUQueryType AsDawnEnum<WGPUQueryType>(const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "occlusion") {
+ return WGPUQueryType_Occlusion;
+ }
+ if (webgpu_enum == "pipeline-statistics") {
+ return WGPUQueryType_PipelineStatistics;
+ }
+ if (webgpu_enum == "timestamp") {
+ return WGPUQueryType_Timestamp;
+ }
+ NOTREACHED();
+ return WGPUQueryType_Force32;
+}
+
+template <>
+WGPUPipelineStatisticName AsDawnEnum<WGPUPipelineStatisticName>(
+ const WTF::String& webgpu_enum) {
+ if (webgpu_enum == "vertex-shader-invocations") {
+ return WGPUPipelineStatisticName_VertexShaderInvocations;
+ }
+ if (webgpu_enum == "clipper-invocations") {
+ return WGPUPipelineStatisticName_ClipperInvocations;
+ }
+ if (webgpu_enum == "clipper-primitives-out") {
+ return WGPUPipelineStatisticName_ClipperPrimitivesOut;
+ }
+ if (webgpu_enum == "fragment-shader-invocations") {
+ return WGPUPipelineStatisticName_FragmentShaderInvocations;
+ }
+ if (webgpu_enum == "compute-shader-invocations") {
+ return WGPUPipelineStatisticName_ComputeShaderInvocations;
+ }
+ NOTREACHED();
+ return WGPUPipelineStatisticName_Force32;
+}
+
+template <>
WGPUTextureFormat AsDawnEnum<WGPUTextureFormat>(
const WTF::String& webgpu_enum) {
if (webgpu_enum.IsNull()) {
@@ -376,6 +416,9 @@ WGPULoadOp AsDawnEnum<WGPULoadOp>(const WTF::String& webgpu_enum) {
template <>
WGPUIndexFormat AsDawnEnum<WGPUIndexFormat>(const WTF::String& webgpu_enum) {
+ if (webgpu_enum.IsNull()) {
+ return WGPUIndexFormat_Undefined;
+ }
if (webgpu_enum == "uint16") {
return WGPUIndexFormat_Uint16;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc
index c8e137b636c..15fc7d89a8a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.cc
@@ -6,6 +6,7 @@
#include "gpu/command_buffer/client/webgpu_interface.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/platform/bindings/microtask.h"
namespace blink {
@@ -62,6 +63,32 @@ uint64_t DeviceTreeObject::GetDeviceClientID() const {
return device_client_serializer_holder_->device_client_id_;
}
+void DeviceTreeObject::EnsureFlush() {
+ bool needs_flush = false;
+ GetInterface()->EnsureAwaitingFlush(
+ device_client_serializer_holder_->device_client_id_, &needs_flush);
+ if (!needs_flush) {
+ // We've already enqueued a task to flush, or the command buffer
+ // is empty. Do nothing.
+ return;
+ }
+ Microtask::EnqueueMicrotask(WTF::Bind(
+ [](scoped_refptr<DawnDeviceClientSerializerHolder> holder) {
+ if (holder->dawn_control_client_->IsDestroyed()) {
+ return;
+ }
+ holder->dawn_control_client_->GetInterface()->FlushAwaitingCommands(
+ holder->device_client_id_);
+ },
+ device_client_serializer_holder_));
+}
+
+// Flush commands up until now on this object's parent device immediately.
+void DeviceTreeObject::FlushNow() {
+ GetInterface()->FlushCommands(
+ device_client_serializer_holder_->device_client_id_);
+}
+
DawnObjectImpl::DawnObjectImpl(GPUDevice* device)
: DeviceTreeObject(device->GetDeviceClientSerializerHolder()),
device_(device) {}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h
index 92c302699eb..63c2d95f9e8 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/dawn_object.h
@@ -88,6 +88,13 @@ class DeviceTreeObject {
uint64_t GetDeviceClientID() const;
+ // Ensure commands up until now on this object's parent device are flushed by
+ // the end of the task.
+ void EnsureFlush();
+
+ // Flush commands up until now on this object's parent device immediately.
+ void FlushNow();
+
protected:
scoped_refptr<DawnDeviceClientSerializerHolder>
device_client_serializer_holder_;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
index 0df4a21fbb5..ac1d0236cc2 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -53,12 +53,9 @@ std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProviderOnMainThread(
return created_context_provider;
}
-} // anonymous namespace
-
-// static
-GPU* GPU::Create(ExecutionContext& execution_context) {
+std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProvider(
+ ExecutionContext& execution_context) {
const KURL& url = execution_context.Url();
-
std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
if (IsMainThread()) {
context_provider =
@@ -74,22 +71,18 @@ GPU* GPU::Create(ExecutionContext& execution_context) {
// error.
return nullptr;
}
+ return context_provider;
+}
- if (!context_provider) {
- // TODO(crbug.com/973017): Collect GPU info and surface context creation
- // error.
- return nullptr;
- }
+} // anonymous namespace
- return MakeGarbageCollected<GPU>(execution_context,
- std::move(context_provider));
+// static
+GPU* GPU::Create(ExecutionContext& execution_context) {
+ return MakeGarbageCollected<GPU>(execution_context);
}
-GPU::GPU(ExecutionContext& execution_context,
- std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
- : ExecutionContextLifecycleObserver(&execution_context),
- dawn_control_client_(base::MakeRefCounted<DawnControlClientHolder>(
- std::move(context_provider))) {}
+GPU::GPU(ExecutionContext& execution_context)
+ : ExecutionContextLifecycleObserver(&execution_context) {}
GPU::~GPU() = default;
@@ -99,6 +92,9 @@ void GPU::Trace(Visitor* visitor) const {
}
void GPU::ContextDestroyed() {
+ if (!dawn_control_client_) {
+ return;
+ }
dawn_control_client_->Destroy();
}
@@ -118,6 +114,29 @@ ScriptPromise GPU::requestAdapter(ScriptState* script_state,
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
+ if (!dawn_control_client_ || dawn_control_client_->IsContextLost()) {
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ // TODO(natlee@microsoft.com): if GPU process is lost, wait for the GPU
+ // process to come back instead of rejecting right away
+ std::unique_ptr<WebGraphicsContext3DProvider> context_provider =
+ CreateContextProvider(*execution_context);
+
+ if (!context_provider) {
+ // Failed to create context provider, won't be able to request adapter
+ // TODO(crbug.com/973017): Collect GPU info and surface context creation
+ // error.
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError, "Fail to request GPUAdapter"));
+ return promise;
+ } else {
+ // Make a new DawnControlClientHolder with the context provider we just
+ // made and set the lost context callback
+ dawn_control_client_ = base::MakeRefCounted<DawnControlClientHolder>(
+ std::move(context_provider));
+ dawn_control_client_->SetLostContextCallback();
+ }
+ }
+
// For now we choose kHighPerformance by default.
gpu::webgpu::PowerPreference power_preference =
gpu::webgpu::PowerPreference::kHighPerformance;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
index 1479ab1e510..9e719040183 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu.h
@@ -18,7 +18,6 @@ namespace blink {
class GPURequestAdapterOptions;
class ScriptPromiseResolver;
class ScriptState;
-class WebGraphicsContext3DProvider;
class DawnControlClientHolder;
class GPU final : public ScriptWrappable,
@@ -27,8 +26,7 @@ class GPU final : public ScriptWrappable,
public:
static GPU* Create(ExecutionContext& execution_context);
- explicit GPU(ExecutionContext& execution_context,
- std::unique_ptr<WebGraphicsContext3DProvider> context_provider);
+ explicit GPU(ExecutionContext& execution_context);
~GPU() override;
// ScriptWrappable overrides
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
index d2ea6c7c40a..d868a34d6d7 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -28,6 +28,10 @@ WGPUDeviceProperties AsDawnType(const GPUDeviceDescriptor* descriptor) {
requested_device_properties.textureCompressionBC =
extension_set.Contains("texture-compression-bc") ||
extension_set.Contains("textureCompressionBC");
+ requested_device_properties.shaderFloat16 =
+ extension_set.Contains("shader-float16");
+ requested_device_properties.timestampQuery =
+ extension_set.Contains("timestamp-query");
return requested_device_properties;
}
@@ -76,6 +80,12 @@ void GPUAdapter::InitializeExtensionNameList() {
extension_name_list_.emplace_back("texture-compression-bc");
extension_name_list_.emplace_back("textureCompressionBC");
}
+ if (adapter_properties_.shaderFloat16) {
+ extension_name_list_.emplace_back("shader-float16");
+ }
+ if (adapter_properties_.timestampQuery) {
+ extension_name_list_.emplace_back("timestamp-query");
+ }
}
ScriptPromise GPUAdapter::requestDevice(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
index 40e4002bbb0..16b2ead0834 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -6,8 +6,10 @@
enum GPUExtensionName {
"texture-compression-bc",
+ "timestamp-query",
// Non-standard extension name string. Remove after a transition period.
- "textureCompressionBC"
+ "textureCompressionBC",
+ "shader-float16"
};
[
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
index 9069f1de24b..301029616a4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
@@ -36,6 +36,12 @@ WGPUBindGroupLayoutEntry AsDawnType(
webgpu_binding->textureComponentType());
dawn_binding.multisampled = webgpu_binding->multisampled();
+ if (dawn_binding.multisampled) {
+ device->AddConsoleWarning(
+ "Creating a GPUBindGroupLayoutEntry with entry.multisampled = true is "
+ "deprecated: set entry.type = \"multisampled-texture\" instead.");
+ }
+
dawn_binding.storageTextureFormat =
AsDawnEnum<WGPUTextureFormat>(webgpu_binding->storageTextureFormat());
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl
index d7ee6c4b1d2..f22cecbb74a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl
@@ -28,6 +28,7 @@ enum GPUBindingType {
"sampler",
"comparison-sampler",
"sampled-texture",
+ "multisampled-texture",
"readonly-storage-texture",
"writeonly-storage-texture",
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
index b4fe4df6dc3..3d590aa0049 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -197,10 +197,9 @@ ScriptPromise GPUBuffer::MapAsyncImpl(ScriptState* script_state,
GetProcs().bufferMapAsync(GetHandle(), mode, map_offset, map_size,
callback->UnboundCallback(),
callback->AsUserdata());
- // WebGPU guarantees callbacks complete in finite time. Flush now so that
- // commands reach the GPU process.
- device_->GetInterface()->FlushCommands();
-
+ // WebGPU guarantees that promises are resolved in finite time so we
+ // need to ensure commands are flushed.
+ EnsureFlush();
return promise;
}
@@ -292,6 +291,16 @@ void GPUBuffer::OnMapAsyncCallback(ScriptPromiseResolver* resolver,
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kOperationError, "Device is lost"));
break;
+ case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError,
+ "Buffer is destroyed before the mapping is resolved"));
+ break;
+ case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback:
+ resolver->Reject(MakeGarbageCollected<DOMException>(
+ DOMExceptionCode::kOperationError,
+ "Buffer is unmapped before the mapping is resolved"));
+ break;
default:
NOTREACHED();
}
@@ -303,10 +312,7 @@ DOMArrayBuffer* GPUBuffer::CreateArrayBufferForMappedData(void* data,
DCHECK_LE(data_length, kLargestMappableSize);
ArrayBufferContents contents(data, data_length,
- [](void* data, size_t length, void* info) {
- // DataDeleter does nothing because Dawn wire
- // owns the memory.
- });
+ v8::BackingStore::EmptyDeleter);
DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(contents);
mapped_array_buffers_.push_back(array_buffer);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
index 482c48f2dc0..65698662129 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture_view.h"
@@ -323,6 +324,22 @@ void GPUCommandEncoder::insertDebugMarker(String markerLabel) {
GetProcs().commandEncoderInsertDebugMarker(GetHandle(), label.c_str());
}
+void GPUCommandEncoder::resolveQuerySet(GPUQuerySet* querySet,
+ uint32_t firstQuery,
+ uint32_t queryCount,
+ GPUBuffer* destination,
+ uint64_t destinationOffset) {
+ GetProcs().commandEncoderResolveQuerySet(
+ GetHandle(), querySet->GetHandle(), firstQuery, queryCount,
+ destination->GetHandle(), destinationOffset);
+}
+
+void GPUCommandEncoder::writeTimestamp(GPUQuerySet* querySet,
+ uint32_t queryIndex) {
+ GetProcs().commandEncoderWriteTimestamp(GetHandle(), querySet->GetHandle(),
+ queryIndex);
+}
+
GPUCommandBuffer* GPUCommandEncoder::finish(
const GPUCommandBufferDescriptor* descriptor) {
std::string label;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
index 04b36eba850..92d221ff16b 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
@@ -18,6 +18,7 @@ class GPUCommandBufferDescriptor;
class GPUCommandEncoderDescriptor;
class GPUComputePassDescriptor;
class GPUComputePassEncoder;
+class GPUQuerySet;
class GPURenderPassDescriptor;
class GPURenderPassEncoder;
class GPUTextureCopyView;
@@ -63,6 +64,12 @@ class GPUCommandEncoder : public DawnObject<WGPUCommandEncoder> {
void pushDebugGroup(String groupLabel);
void popDebugGroup();
void insertDebugMarker(String markerLabel);
+ void resolveQuerySet(GPUQuerySet* querySet,
+ uint32_t firstQuery,
+ uint32_t queryCount,
+ GPUBuffer* destination,
+ uint64_t destinationOffset);
+ void writeTimestamp(GPUQuerySet* querySet, uint32_t queryIndex);
GPUCommandBuffer* finish(const GPUCommandBufferDescriptor* descriptor);
private:
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
index 97600ac9f5b..d054757ff76 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
@@ -36,5 +36,14 @@
void popDebugGroup();
void insertDebugMarker(USVString markerLabel);
+ void resolveQuerySet(
+ GPUQuerySet querySet,
+ GPUSize32 firstQuery,
+ GPUSize32 queryCount,
+ GPUBuffer destination,
+ GPUSize64 destinationOffset);
+
+ void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
+
GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc
index f8baf24662c..7e4738d47b2 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_buffer.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
namespace blink {
@@ -81,6 +82,12 @@ void GPUComputePassEncoder::dispatchIndirect(GPUBuffer* indirectBuffer,
GetHandle(), indirectBuffer->GetHandle(), indirectOffset);
}
+void GPUComputePassEncoder::writeTimestamp(GPUQuerySet* querySet,
+ uint32_t queryIndex) {
+ GetProcs().computePassEncoderWriteTimestamp(
+ GetHandle(), querySet->GetHandle(), queryIndex);
+}
+
void GPUComputePassEncoder::endPass() {
GetProcs().computePassEncoderEndPass(GetHandle());
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h
index 7d8dead8daa..26cc4d92c57 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.h
@@ -14,6 +14,7 @@ namespace blink {
class GPUBindGroup;
class GPUBuffer;
class GPUComputePipeline;
+class GPUQuerySet;
class GPUComputePassEncoder : public DawnObject<WGPUComputePassEncoder>,
public GPUProgrammablePassEncoder {
@@ -40,6 +41,7 @@ class GPUComputePassEncoder : public DawnObject<WGPUComputePassEncoder>,
void setPipeline(GPUComputePipeline* pipeline);
void dispatch(uint32_t x, uint32_t y, uint32_t z);
void dispatchIndirect(GPUBuffer* indirectBuffer, uint64_t indirectOffset);
+ void writeTimestamp(GPUQuerySet* querySet, uint32_t queryIndex);
void endPass();
private:
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
index ad0cc80c8d1..858b075ae86 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
@@ -13,7 +13,7 @@
optional GPUSize32 z = 1);
void dispatchIndirect(GPUBuffer indirectBuffer,
GPUSize64 indirectOffset);
-
+ void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
void endPass();
};
GPUComputePassEncoder includes GPUProgrammablePassEncoder;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 2ee9d22b024..15fb088ced6 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device_lost_info.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_queue.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
@@ -68,11 +69,16 @@ GPUDevice::GPUDevice(ExecutionContext* execution_context,
GetProcs().deviceGetDefaultQueue(GetHandle()))),
lost_property_(MakeGarbageCollected<LostProperty>(execution_context)),
error_callback_(BindRepeatingDawnCallback(&GPUDevice::OnUncapturedError,
- WrapWeakPersistent(this))) {
+ WrapWeakPersistent(this))),
+ lost_callback_(BindDawnCallback(&GPUDevice::OnDeviceLostError,
+ WrapWeakPersistent(this))) {
DCHECK(dawn_control_client->GetInterface()->GetDevice(client_id));
GetProcs().deviceSetUncapturedErrorCallback(
GetHandle(), error_callback_->UnboundRepeatingCallback(),
error_callback_->AsUserdata());
+ GetProcs().deviceSetDeviceLostCallback(GetHandle(),
+ lost_callback_->UnboundCallback(),
+ lost_callback_->AsUserdata());
if (extension_name_list_.Contains("textureCompressionBC")) {
AddConsoleWarning(
@@ -112,16 +118,10 @@ void GPUDevice::AddConsoleWarning(const char* message) {
void GPUDevice::OnUncapturedError(WGPUErrorType errorType,
const char* message) {
DCHECK_NE(errorType, WGPUErrorType_NoError);
+ DCHECK_NE(errorType, WGPUErrorType_DeviceLost);
LOG(ERROR) << "GPUDevice: " << message;
AddConsoleWarning(message);
- // TODO: Use device lost callback instead of uncaptured error callback.
- if (errorType == WGPUErrorType_DeviceLost &&
- lost_property_->GetState() == LostProperty::kPending) {
- auto* device_lost_info = MakeGarbageCollected<GPUDeviceLostInfo>(message);
- lost_property_->Resolve(device_lost_info);
- }
-
GPUUncapturedErrorEventInit* init = GPUUncapturedErrorEventInit::Create();
if (errorType == WGPUErrorType_Validation) {
auto* error = MakeGarbageCollected<GPUValidationError>(message);
@@ -139,6 +139,15 @@ void GPUDevice::OnUncapturedError(WGPUErrorType errorType,
event_type_names::kUncapturederror, init));
}
+void GPUDevice::OnDeviceLostError(const char* message) {
+ AddConsoleWarning(message);
+
+ if (lost_property_->GetState() == LostProperty::kPending) {
+ auto* device_lost_info = MakeGarbageCollected<GPUDeviceLostInfo>(message);
+ lost_property_->Resolve(device_lost_info);
+ }
+}
+
GPUAdapter* GPUDevice::adapter() const {
return adapter_;
}
@@ -212,6 +221,11 @@ GPURenderBundleEncoder* GPUDevice::createRenderBundleEncoder(
return GPURenderBundleEncoder::Create(this, descriptor);
}
+GPUQuerySet* GPUDevice::createQuerySet(
+ const GPUQuerySetDescriptor* descriptor) {
+ return GPUQuerySet::Create(this, descriptor);
+}
+
void GPUDevice::pushErrorScope(const WTF::String& filter) {
GetProcs().devicePushErrorScope(GetHandle(),
AsDawnEnum<WGPUErrorFilter>(filter));
@@ -234,11 +248,9 @@ ScriptPromise GPUDevice::popErrorScope(ScriptState* script_state) {
return promise;
}
- // WebGPU guarantees callbacks complete in finite time. Flush now so that
- // commands reach the GPU process. TODO(enga): This should happen at the end
- // of the task.
- GetInterface()->FlushCommands();
-
+ // WebGPU guarantees that promises are resolved in finite time so we
+ // need to ensure commands are flushed.
+ EnsureFlush();
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h
index 9d161c4bcaf..2ebe2bde54e 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -33,6 +33,8 @@ class GPUDeviceDescriptor;
class GPUDeviceLostInfo;
class GPUPipelineLayout;
class GPUPipelineLayoutDescriptor;
+class GPUQuerySet;
+class GPUQuerySetDescriptor;
class GPUQueue;
class GPURenderBundleEncoder;
class GPURenderBundleEncoderDescriptor;
@@ -96,6 +98,8 @@ class GPUDevice final : public EventTargetWithInlineData,
GPURenderBundleEncoder* createRenderBundleEncoder(
const GPURenderBundleEncoderDescriptor* descriptor);
+ GPUQuerySet* createQuerySet(const GPUQuerySetDescriptor* descriptor);
+
void pushErrorScope(const WTF::String& filter);
ScriptPromise popErrorScope(ScriptState* script_state);
@@ -112,6 +116,7 @@ class GPUDevice final : public EventTargetWithInlineData,
ScriptPromiseProperty<Member<GPUDeviceLostInfo>, ToV8UndefinedGenerator>;
void OnUncapturedError(WGPUErrorType errorType, const char* message);
+ void OnDeviceLostError(const char* message);
void OnPopErrorScopeCallback(ScriptPromiseResolver* resolver,
WGPUErrorType type,
@@ -124,6 +129,8 @@ class GPUDevice final : public EventTargetWithInlineData,
std::unique_ptr<
DawnCallback<base::RepeatingCallback<void(WGPUErrorType, const char*)>>>
error_callback_;
+ std::unique_ptr<DawnCallback<base::OnceCallback<void(const char*)>>>
+ lost_callback_;
static constexpr int kMaxAllowedConsoleWarnings = 500;
int allowed_console_warnings_remaining_ = kMaxAllowedConsoleWarnings;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl
index 338fe764833..aa1da249d33 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -28,6 +28,8 @@
GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
+ GPUQuerySet createQuerySet(GPUQuerySetDescriptor descriptor);
+
void pushErrorScope(GPUErrorFilter filter);
[CallWith=ScriptState] Promise<GPUError?> popErrorScope();
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc
index af59d02ce0c..8ee1dd5776a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_fence.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_fence.h"
+#include "gpu/command_buffer/client/webgpu_interface.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/webgpu/dawn_callback.h"
@@ -55,7 +56,9 @@ ScriptPromise GPUFence::onCompletion(ScriptState* script_state,
GetProcs().fenceOnCompletion(GetHandle(), value, callback->UnboundCallback(),
callback->AsUserdata());
-
+ // WebGPU guarantees that promises are resolved in finite time so we
+ // need to ensure commands are flushed.
+ EnsureFlush();
return promise;
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc
new file mode 100644
index 00000000000..ddd49f65bca
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.cc
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
+
+#include "gpu/command_buffer/client/webgpu_interface.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_query_set_descriptor.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+
+namespace blink {
+
+// static
+GPUQuerySet* GPUQuerySet::Create(GPUDevice* device,
+ const GPUQuerySetDescriptor* webgpu_desc) {
+ DCHECK(device);
+ DCHECK(webgpu_desc);
+
+ WGPUQuerySetDescriptor dawn_desc = {};
+ dawn_desc.nextInChain = nullptr;
+ dawn_desc.type = AsDawnEnum<WGPUQueryType>(webgpu_desc->type());
+ dawn_desc.count = webgpu_desc->count();
+
+ std::unique_ptr<WGPUPipelineStatisticName[]> pipeline_statistics;
+ if (webgpu_desc->hasPipelineStatistics()) {
+ pipeline_statistics = AsDawnEnum<WGPUPipelineStatisticName>(
+ webgpu_desc->pipelineStatistics());
+ dawn_desc.pipelineStatistics = pipeline_statistics.get();
+ dawn_desc.pipelineStatisticsCount =
+ webgpu_desc->pipelineStatistics().size();
+ }
+
+ std::string label;
+ if (webgpu_desc->hasLabel()) {
+ label = webgpu_desc->label().Utf8();
+ dawn_desc.label = label.c_str();
+ }
+
+ return MakeGarbageCollected<GPUQuerySet>(
+ device,
+ device->GetProcs().deviceCreateQuerySet(device->GetHandle(), &dawn_desc));
+}
+
+GPUQuerySet::GPUQuerySet(GPUDevice* device, WGPUQuerySet querySet)
+ : DawnObject<WGPUQuerySet>(device, querySet) {}
+
+GPUQuerySet::~GPUQuerySet() {
+ if (IsDawnControlClientDestroyed()) {
+ return;
+ }
+ GetProcs().querySetRelease(GetHandle());
+}
+
+void GPUQuerySet::destroy() {
+ GetProcs().querySetDestroy(GetHandle());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h
new file mode 100644
index 00000000000..c26749382db
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_QUERY_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_QUERY_SET_H_
+
+#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+class GPUQuerySetDescriptor;
+
+class GPUQuerySet : public DawnObject<WGPUQuerySet> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ static GPUQuerySet* Create(GPUDevice* device,
+ const GPUQuerySetDescriptor* webgpu_desc);
+ explicit GPUQuerySet(GPUDevice* device, WGPUQuerySet querySet);
+ ~GPUQuerySet() override;
+
+ // gpu_queryset.idl
+ void destroy();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GPUQuerySet);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_QUERY_SET_H_
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl
new file mode 100644
index 00000000000..d9457806831
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set.idl
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium 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://gpuweb.github.io/gpuweb/
+
+[
+ Exposed(Window WebGPU, Worker WebGPU)
+] interface GPUQuerySet {
+ void destroy();
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set_descriptor.idl
new file mode 100644
index 00000000000..727f98de966
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_query_set_descriptor.idl
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase {
+ required GPUQueryType type;
+ required GPUSize32 count;
+ sequence<GPUPipelineStatisticName> pipelineStatistics = [];
+};
+
+enum GPUQueryType {
+ "occlusion",
+ "pipeline-statistics",
+ "timestamp"
+};
+
+enum GPUPipelineStatisticName {
+ "vertex-shader-invocations",
+ "clipper-invocations",
+ "clipper-primitives-out",
+ "fragment-shader-invocations",
+ "compute-shader-invocations"
+};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
index 22ec1ed77c6..4ae018883f4 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -100,15 +100,16 @@ bool IsValidCopyIB2TDestinationFormat(WGPUTextureFormat dawn_texture_format) {
}
bool CanUploadThroughGPU(StaticBitmapImage* image,
- const CanvasColorParams& color_param,
GPUTexture* dest_texture) {
// Cannot handle top left origin image
if (image->CurrentFrameOrientation().Orientation() !=
ImageOrientationEnum::kOriginBottomLeft) {
return false;
}
+
// Cannot handle source and dest texture have uncompatible format
- if (!AreCompatibleFormatForImageBitmapGPUCopy(color_param.GetSkColorType(),
+ SkImageInfo image_info = image->PaintImageForCurrentFrame().GetSkImageInfo();
+ if (!AreCompatibleFormatForImageBitmapGPUCopy(image_info.colorType(),
dest_texture->Format())) {
return false;
}
@@ -146,16 +147,17 @@ void GPUQueue::submit(const HeapVector<Member<GPUCommandBuffer>>& buffers) {
GetProcs().queueSubmit(GetHandle(), buffers.size(), commandBuffers.get());
// WebGPU guarantees that submitted commands finish in finite time so we
- // flush commands to the GPU process now.
- device_->GetInterface()->FlushCommands();
+ // need to ensure commands are flushed. Flush immediately so the GPU process
+ // eagerly processes commands to maximize throughput.
+ FlushNow();
}
void GPUQueue::signal(GPUFence* fence, uint64_t signal_value) {
GetProcs().queueSignal(GetHandle(), fence->GetHandle(), signal_value);
// Signaling a fence adds a callback to update the fence value to the
// completed value. WebGPU guarantees that the fence completion is
- // observable in finite time so we flush commands to the GPU process now.
- device_->GetInterface()->FlushCommands();
+ // observable in finite time so we need to ensure commands are flushed.
+ EnsureFlush();
}
GPUFence* GPUQueue::createFence(const GPUFenceDescriptor* descriptor) {
@@ -335,6 +337,13 @@ void GPUQueue::copyImageBitmapToTexture(
return;
}
+ // ImageBitmap shouldn't in closed state.
+ if (source->imageBitmap()->IsNeutered()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "ImageBitmap is closed.");
+ return;
+ }
+
scoped_refptr<StaticBitmapImage> image = source->imageBitmap()->BitmapImage();
@@ -348,10 +357,18 @@ void GPUQueue::copyImageBitmapToTexture(
WGPUOrigin3D origin_in_image_bitmap =
GPUOrigin2DToWGPUOrigin3D(&(source->origin()));
+ // Validate copy depth
+ if (dawn_copy_size.depth > 1) {
+ GetProcs().deviceInjectError(device_->GetHandle(), WGPUErrorType_Validation,
+ "Copy depth is out of bounds of imageBitmap.");
+ return;
+ }
+
// Validate origin value
- if (static_cast<uint32_t>(image->width()) <= origin_in_image_bitmap.x ||
- static_cast<uint32_t>(image->height()) <= origin_in_image_bitmap.y) {
- exception_state.ThrowRangeError(
+ if (static_cast<uint32_t>(image->width()) < origin_in_image_bitmap.x ||
+ static_cast<uint32_t>(image->height()) < origin_in_image_bitmap.y) {
+ GetProcs().deviceInjectError(
+ device_->GetHandle(), WGPUErrorType_Validation,
"Copy origin is out of bounds of imageBitmap.");
return;
}
@@ -359,8 +376,8 @@ void GPUQueue::copyImageBitmapToTexture(
// Validate the copy rect is inside the imageBitmap
if (image->width() - origin_in_image_bitmap.x < dawn_copy_size.width ||
image->height() - origin_in_image_bitmap.y < dawn_copy_size.height) {
- exception_state.ThrowRangeError(
- "Copy rect is out of bounds of imageBitmap.");
+ GetProcs().deviceInjectError(device_->GetHandle(), WGPUErrorType_Validation,
+ "Copy rect is out of bounds of imageBitmap.");
return;
}
@@ -371,14 +388,13 @@ void GPUQueue::copyImageBitmapToTexture(
return;
}
- const CanvasColorParams& color_params =
- source->imageBitmap()->GetCanvasColorParams();
+ bool isNoopCopy = dawn_copy_size.width == 0 || dawn_copy_size.height == 0 ||
+ dawn_copy_size.depth == 0;
// TODO(shaobo.yan@intel.com): Implement GPU copy path
- // Try GPU path first.
- if (image->IsTextureBacked()) { // Try GPU uploading path.
- if (CanUploadThroughGPU(image.get(), color_params,
- destination->texture())) {
+ // Try GPU path first and delegate noop copy to CPU path.
+ if (image->IsTextureBacked() && !isNoopCopy) { // Try GPU uploading path.
+ if (CanUploadThroughGPU(image.get(), destination->texture())) {
if (CopyContentFromGPU(image.get(), origin_in_image_bitmap,
dawn_copy_size, dawn_destination)) {
return;
@@ -388,16 +404,14 @@ void GPUQueue::copyImageBitmapToTexture(
image = image->MakeUnaccelerated();
}
// CPU path is the fallback path and should always work.
- if (!CopyContentFromCPU(image.get(), color_params, origin_in_image_bitmap,
- dawn_copy_size, dawn_destination,
- destination->texture()->Format())) {
+ if (!CopyContentFromCPU(image.get(), origin_in_image_bitmap, dawn_copy_size,
+ dawn_destination, destination->texture()->Format())) {
exception_state.ThrowTypeError("Failed to copy content from imageBitmap.");
return;
}
}
bool GPUQueue::CopyContentFromCPU(StaticBitmapImage* image,
- const CanvasColorParams& color_params,
const WGPUOrigin3D& origin,
const WGPUExtent3D& copy_size,
const WGPUTextureCopyView& destination,
@@ -409,11 +423,13 @@ bool GPUQueue::CopyContentFromCPU(StaticBitmapImage* image,
WebGPUImageUploadSizeInfo info = ComputeImageBitmapWebGPUUploadSizeInfo(
image_data_rect, dest_texture_format);
+ bool isNoopCopy = info.size_in_bytes == 0 || copy_size.depth == 0;
+
// Create a mapped buffer to receive image bitmap contents
WGPUBufferDescriptor buffer_desc = {};
buffer_desc.usage = WGPUBufferUsage_CopySrc;
buffer_desc.size = info.size_in_bytes;
- buffer_desc.mappedAtCreation = true;
+ buffer_desc.mappedAtCreation = !isNoopCopy;
if (buffer_desc.size > uint64_t(std::numeric_limits<size_t>::max())) {
return false;
@@ -422,17 +438,22 @@ bool GPUQueue::CopyContentFromCPU(StaticBitmapImage* image,
WGPUBuffer buffer =
GetProcs().deviceCreateBuffer(device_->GetHandle(), &buffer_desc);
- void* data = GetProcs().bufferGetMappedRange(buffer, 0, size);
- if (!CopyBytesFromImageBitmapForWebGPU(
- image, base::span<uint8_t>(static_cast<uint8_t*>(data), size),
- image_data_rect, color_params, dest_texture_format)) {
- // Release the buffer.
- GetProcs().bufferRelease(buffer);
- return false;
- }
+ // Bypass extract source content in noop copy but follow the copy path
+ // for validation.
+ if (!isNoopCopy) {
+ void* data = GetProcs().bufferGetMappedRange(buffer, 0, size);
- GetProcs().bufferUnmap(buffer);
+ if (!CopyBytesFromImageBitmapForWebGPU(
+ image, base::span<uint8_t>(static_cast<uint8_t*>(data), size),
+ image_data_rect, dest_texture_format)) {
+ // Release the buffer.
+ GetProcs().bufferRelease(buffer);
+ return false;
+ }
+
+ GetProcs().bufferUnmap(buffer);
+ }
// Start a B2T copy to move contents from buffer to destination texture
WGPUBufferCopyView dawn_intermediate = {};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h
index 3c6ab74f99a..7ada7446e4a 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_queue.h
@@ -11,7 +11,6 @@
namespace blink {
-class CanvasColorParams;
class DawnTextureFromImageBitmap;
class ExceptionState;
class GPUBuffer;
@@ -77,7 +76,6 @@ class GPUQueue : public DawnObject<WGPUQueue> {
private:
bool CopyContentFromCPU(StaticBitmapImage* image,
- const CanvasColorParams& color_params,
const WGPUOrigin3D& origin,
const WGPUExtent3D& copy_size,
const WGPUTextureCopyView& destination,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc
index cfacee835ef..ef9ecf86eb9 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.cc
@@ -112,10 +112,28 @@ void GPURenderBundleEncoder::setPipeline(GPURenderPipeline* pipeline) {
void GPURenderBundleEncoder::setIndexBuffer(GPUBuffer* buffer,
uint64_t offset,
uint64_t size) {
+ device_->AddConsoleWarning(
+ "Calling setIndexBuffer without a GPUIndexFormat is deprecated.");
GetProcs().renderBundleEncoderSetIndexBuffer(GetHandle(), buffer->GetHandle(),
offset, size);
}
+void GPURenderBundleEncoder::setIndexBuffer(GPUBuffer* buffer,
+ const WTF::String& format,
+ uint64_t offset,
+ uint64_t size,
+ ExceptionState& exception_state) {
+ if (format != "uint16" && format != "uint32") {
+ exception_state.ThrowTypeError(
+ "The provided value '" + format +
+ "' is not a valid enum value of type GPUIndexFormat.");
+ return;
+ }
+ GetProcs().renderBundleEncoderSetIndexBufferWithFormat(
+ GetHandle(), buffer->GetHandle(), AsDawnEnum<WGPUIndexFormat>(format),
+ offset, size);
+}
+
void GPURenderBundleEncoder::setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
uint64_t offset,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h
index 94528584812..70d2c7b8988 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.h
@@ -47,6 +47,11 @@ class GPURenderBundleEncoder : public DawnObject<WGPURenderBundleEncoder>,
void setPipeline(GPURenderPipeline* pipeline);
void setIndexBuffer(GPUBuffer* buffer, uint64_t offset, uint64_t size);
+ void setIndexBuffer(GPUBuffer* buffer,
+ const WTF::String& format,
+ uint64_t offset,
+ uint64_t size,
+ ExceptionState& exception_state);
void setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
uint64_t offset,
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl
index f7f694c3b1e..9061bc26e6c 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl
@@ -12,20 +12,32 @@
void setIndexBuffer(GPUBuffer buffer,
optional GPUSize64 offset = 0,
optional GPUSize64 size = 0);
+ // TODO: the format argument here should be a GPUIndexFormat enum, but that
+ // is causing problems with the bindings generator when paired with the
+ // overload. The above overload is deprecated and will be removed soon,
+ // which will allow us to use the correct type here. In the meantime we'll
+ // validate that the given string is one of the expected enum values
+ // manually.
+ [RaisesException]
+ void setIndexBuffer(GPUBuffer buffer,
+ DOMString format,
+ optional GPUSize64 offset = 0,
+ optional GPUSize64 size = 0);
+
void setVertexBuffer(GPUIndex32 slot,
GPUBuffer buffer,
optional GPUSize64 offset = 0,
optional GPUSize64 size = 0);
- void draw(GPUSize32 vertexCount,
- optional GPUSize32 instanceCount = 1,
- optional GPUSize32 firstVertex = 0,
- optional GPUSize32 firstInstance = 0);
- void drawIndexed(GPUSize32 indexCount,
- optional GPUSize32 instanceCount = 1,
- optional GPUSize32 firstIndex = 0,
- optional GPUSignedOffset32 baseVertex = 0,
- optional GPUSize32 firstInstance = 0);
+ [NoAllocDirectCall] void draw(GPUSize32 vertexCount,
+ optional GPUSize32 instanceCount = 1,
+ optional GPUSize32 firstVertex = 0,
+ optional GPUSize32 firstInstance = 0);
+ [NoAllocDirectCall] void drawIndexed(GPUSize32 indexCount,
+ optional GPUSize32 instanceCount = 1,
+ optional GPUSize32 firstIndex = 0,
+ optional GPUSignedOffset32 baseVertex = 0,
+ optional GPUSize32 firstInstance = 0);
void drawIndirect(GPUBuffer indirectBuffer,
GPUSize64 indirectOffset);
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc
index fba815fa1bc..d13bb1043b5 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/modules/webgpu/gpu_bind_group.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_buffer.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_render_bundle.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
@@ -110,10 +111,28 @@ void GPURenderPassEncoder::setScissorRect(uint32_t x,
void GPURenderPassEncoder::setIndexBuffer(GPUBuffer* buffer,
uint64_t offset,
uint64_t size) {
+ device_->AddConsoleWarning(
+ "Calling setIndexBuffer without a GPUIndexFormat is deprecated.");
GetProcs().renderPassEncoderSetIndexBuffer(GetHandle(), buffer->GetHandle(),
offset, size);
}
+void GPURenderPassEncoder::setIndexBuffer(GPUBuffer* buffer,
+ const WTF::String& format,
+ uint64_t offset,
+ uint64_t size,
+ ExceptionState& exception_state) {
+ if (format != "uint16" && format != "uint32") {
+ exception_state.ThrowTypeError(
+ "The provided value '" + format +
+ "' is not a valid enum value of type GPUIndexFormat.");
+ return;
+ }
+ GetProcs().renderPassEncoderSetIndexBufferWithFormat(
+ GetHandle(), buffer->GetHandle(), AsDawnEnum<WGPUIndexFormat>(format),
+ offset, size);
+}
+
void GPURenderPassEncoder::setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
const uint64_t offset,
@@ -160,6 +179,12 @@ void GPURenderPassEncoder::executeBundles(
dawn_bundles.get());
}
+void GPURenderPassEncoder::writeTimestamp(GPUQuerySet* querySet,
+ uint32_t queryIndex) {
+ GetProcs().renderPassEncoderWriteTimestamp(GetHandle(), querySet->GetHandle(),
+ queryIndex);
+}
+
void GPURenderPassEncoder::endPass() {
GetProcs().renderPassEncoderEndPass(GetHandle());
}
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h
index 494b3de2481..cfbb33e32b0 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.h
@@ -16,6 +16,7 @@ class GPUBuffer;
class DoubleSequenceOrGPUColorDict;
class GPURenderBundle;
class GPURenderPipeline;
+class GPUQuerySet;
class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
public GPUProgrammablePassEncoder {
@@ -52,6 +53,11 @@ class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
float maxDepth);
void setScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
void setIndexBuffer(GPUBuffer* buffer, uint64_t offset, uint64_t size);
+ void setIndexBuffer(GPUBuffer* buffer,
+ const WTF::String& format,
+ uint64_t offset,
+ uint64_t size,
+ ExceptionState& exception_state);
void setVertexBuffer(uint32_t slot,
const GPUBuffer* buffer,
const uint64_t offset,
@@ -68,6 +74,7 @@ class GPURenderPassEncoder : public DawnObject<WGPURenderPassEncoder>,
void drawIndirect(GPUBuffer* indirectBuffer, uint64_t indirectOffset);
void drawIndexedIndirect(GPUBuffer* indirectBuffer, uint64_t indirectOffset);
void executeBundles(const HeapVector<Member<GPURenderBundle>>& bundles);
+ void writeTimestamp(GPUQuerySet* querySet, uint32_t queryIndex);
void endPass();
private:
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
index 6d817591cfb..6ac8535eca3 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
@@ -18,6 +18,7 @@
void setStencilReference(GPUStencilValue reference);
void executeBundles(sequence<GPURenderBundle> bundles);
+ void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
void endPass();
};
GPURenderPassEncoder includes GPUProgrammablePassEncoder;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
index 2b44420412c..e29a8ee4285 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -236,20 +236,44 @@ GPURenderPipeline* GPURenderPipeline::Create(
dawn_desc.fragmentStage = nullptr;
}
+ dawn_desc.primitiveTopology =
+ AsDawnEnum<WGPUPrimitiveTopology>(webgpu_desc->primitiveTopology());
+
v8::Isolate* isolate = script_state->GetIsolate();
ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
"GPUVertexStateDescriptor");
WGPUVertexStateInfo vertex_state_info = GPUVertexStateAsWGPUVertexState(
isolate, webgpu_desc->vertexState(), exception_state);
- dawn_desc.vertexState = &std::get<0>(vertex_state_info);
+ WGPUVertexStateDescriptor dawn_vertex_state = std::get<0>(vertex_state_info);
+
+ // TODO(crbug.com/1121762): Remove these checks after a deprecation period.
+ if (dawn_vertex_state.indexFormat == WGPUIndexFormat_Undefined) {
+ dawn_vertex_state.indexFormat = WGPUIndexFormat_Uint32;
+
+ if (dawn_desc.primitiveTopology == WGPUPrimitiveTopology_LineStrip ||
+ dawn_desc.primitiveTopology == WGPUPrimitiveTopology_TriangleStrip) {
+ device->AddConsoleWarning(
+ "Creating a GPUVertexStateDescriptor with a default indexFormat is "
+ "deprecated: Specify an explicit GPUIndexFormat when using "
+ "'line-strip' or 'triangle-strip' primitive topologies.");
+ }
+ } else if (dawn_desc.primitiveTopology == WGPUPrimitiveTopology_PointList ||
+ dawn_desc.primitiveTopology == WGPUPrimitiveTopology_LineList ||
+ dawn_desc.primitiveTopology ==
+ WGPUPrimitiveTopology_TriangleList) {
+ device->AddConsoleWarning(
+ "Creating a GPUVertexStateDescriptor with an explicit indexFormat is "
+ "deprecated when using 'point-list', 'line-list', or 'triangle-list' "
+ "primitive topologies: Specify the GPUIndexFormat when calling "
+ "setIndexBuffer() instead.");
+ }
+
+ dawn_desc.vertexState = &dawn_vertex_state;
if (exception_state.HadException()) {
return nullptr;
}
- dawn_desc.primitiveTopology =
- AsDawnEnum<WGPUPrimitiveTopology>(webgpu_desc->primitiveTopology());
-
WGPURasterizationStateDescriptor rasterization_state;
rasterization_state = AsDawnType(webgpu_desc->rasterizationState());
dawn_desc.rasterizationState = &rasterization_state;
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl b/chromium/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
index 7a991d1a7fd..7073c0f627d 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
+++ b/chromium/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
@@ -5,7 +5,7 @@
// https://gpuweb.github.io/gpuweb/
dictionary GPUVertexStateDescriptor {
- GPUIndexFormat indexFormat = "uint32";
+ GPUIndexFormat indexFormat;
// TODO(crbug.com/951629): Make this a sequence of nullables.
object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferLayoutDescriptor
};
diff --git a/chromium/third_party/blink/renderer/modules/webgpu/idls.gni b/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
index c4cc0634d57..31dad915217 100644
--- a/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webgpu/idls.gni
@@ -21,6 +21,7 @@ modules_idl_files = [
"gpu_map_mode.idl",
"gpu_out_of_memory_error.idl",
"gpu_pipeline_layout.idl",
+ "gpu_query_set.idl",
"gpu_queue.idl",
"gpu_render_bundle.idl",
"gpu_render_bundle_encoder.idl",
@@ -64,6 +65,7 @@ modules_dictionary_idl_files = [
"gpu_pipeline_descriptor_base.idl",
"gpu_pipeline_layout_descriptor.idl",
"gpu_programmable_stage_descriptor.idl",
+ "gpu_query_set_descriptor.idl",
"gpu_rasterization_state_descriptor.idl",
"gpu_render_bundle_descriptor.idl",
"gpu_render_bundle_encoder_descriptor.idl",
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 25681853b66..442923960c9 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc
@@ -31,6 +31,10 @@
#include "third_party/blink/renderer/modules/webmidi/midi_access.h"
#include <memory>
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
@@ -42,6 +46,7 @@
#include "third_party/blink/renderer/modules/webmidi/midi_output_map.h"
#include "third_party/blink/renderer/modules/webmidi/midi_port.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
namespace blink {
@@ -60,12 +65,12 @@ PortState ToDeviceState(PortState state) {
} // namespace
MIDIAccess::MIDIAccess(
- std::unique_ptr<MIDIDispatcher> dispatcher,
+ MIDIDispatcher* dispatcher,
bool sysex_enabled,
const Vector<MIDIAccessInitializer::PortDescriptor>& ports,
ExecutionContext* execution_context)
: ExecutionContextLifecycleObserver(execution_context),
- dispatcher_(std::move(dispatcher)),
+ dispatcher_(dispatcher),
sysex_enabled_(sysex_enabled),
has_pending_activity_(false) {
dispatcher_->SetClient(this);
@@ -80,14 +85,26 @@ MIDIAccess::MIDIAccess(
port.version, ToDeviceState(port.state)));
}
}
+ constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
+ IdentifiableSurface::Type::kWebFeature,
+ WebFeature::kRequestMIDIAccess_ObscuredByFootprinting);
+ if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
+ IdentifiableTokenBuilder builder;
+ for (const auto& port : ports) {
+ builder.AddToken(IdentifiabilityBenignStringToken(port.id));
+ builder.AddToken(IdentifiabilityBenignStringToken(port.name));
+ builder.AddToken(IdentifiabilityBenignStringToken(port.manufacturer));
+ builder.AddToken(IdentifiabilityBenignStringToken(port.version));
+ builder.AddToken(port.type);
+ }
+ IdentifiabilityMetricBuilder(execution_context->UkmSourceID())
+ .Set(surface, builder.GetToken())
+ .Record(execution_context->UkmRecorder());
+ }
}
MIDIAccess::~MIDIAccess() = default;
-void MIDIAccess::Dispose() {
- dispatcher_.reset();
-}
-
EventListener* MIDIAccess::onstatechange() {
return GetAttributeEventListener(event_type_names::kStatechange);
}
@@ -202,11 +219,8 @@ void MIDIAccess::SendMIDIData(unsigned port_index,
dispatcher_->SendMIDIData(port_index, data, length, time_stamp);
}
-void MIDIAccess::ContextDestroyed() {
- dispatcher_.reset();
-}
-
void MIDIAccess::Trace(Visitor* visitor) const {
+ visitor->Trace(dispatcher_);
visitor->Trace(inputs_);
visitor->Trace(outputs_);
EventTargetWithInlineData::Trace(visitor);
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 2ac7887763d..de97b1c5a12 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.h
@@ -55,10 +55,9 @@ class MIDIAccess final : public EventTargetWithInlineData,
public ExecutionContextLifecycleObserver,
public MIDIDispatcher::Client {
DEFINE_WRAPPERTYPEINFO();
- USING_PRE_FINALIZER(MIDIAccess, Dispose);
public:
- MIDIAccess(std::unique_ptr<MIDIDispatcher>,
+ MIDIAccess(MIDIDispatcher*,
bool sysex_enabled,
const Vector<MIDIAccessInitializer::PortDescriptor>&,
ExecutionContext*);
@@ -84,7 +83,7 @@ class MIDIAccess final : public EventTargetWithInlineData,
bool HasPendingActivity() const final;
// ExecutionContextLifecycleObserver
- void ContextDestroyed() override;
+ void ContextDestroyed() override {}
// MIDIDispatcher::Client
void DidAddInputPort(const String& id,
@@ -124,9 +123,7 @@ class MIDIAccess final : public EventTargetWithInlineData,
void Trace(Visitor*) const override;
private:
- void Dispose();
-
- std::unique_ptr<MIDIDispatcher> dispatcher_;
+ Member<MIDIDispatcher> dispatcher_;
bool sysex_enabled_;
bool has_pending_activity_;
HeapVector<Member<MIDIInput>> inputs_;
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 549b63ae541..df8c396854c 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
@@ -34,13 +34,7 @@ MIDIAccessInitializer::MIDIAccessInitializer(ScriptState* script_state,
options_(options),
permission_service_(ExecutionContext::From(script_state)) {}
-void MIDIAccessInitializer::Dispose() {
- dispatcher_.reset();
-}
-
void MIDIAccessInitializer::ContextDestroyed() {
- dispatcher_.reset();
-
ScriptPromiseResolver::ContextDestroyed();
}
@@ -108,7 +102,7 @@ void MIDIAccessInitializer::DidStartSession(Result result) {
break;
case Result::OK:
return Resolve(MakeGarbageCollected<MIDIAccess>(
- std::move(dispatcher_), options_->hasSysex() && options_->sysex(),
+ dispatcher_, options_->hasSysex() && options_->sysex(),
port_descriptors_, GetExecutionContext()));
case Result::NOT_SUPPORTED:
return Reject(MakeGarbageCollected<DOMException>(
@@ -125,6 +119,7 @@ void MIDIAccessInitializer::DidStartSession(Result result) {
}
void MIDIAccessInitializer::Trace(Visitor* visitor) const {
+ visitor->Trace(dispatcher_);
visitor->Trace(options_);
visitor->Trace(permission_service_);
ScriptPromiseResolver::Trace(visitor);
@@ -137,10 +132,7 @@ ExecutionContext* MIDIAccessInitializer::GetExecutionContext() const {
void MIDIAccessInitializer::StartSession() {
DCHECK(!dispatcher_);
- // See https://bit.ly/2S0zRAS for task types.
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
- dispatcher_ = std::make_unique<MIDIDispatcher>(task_runner);
+ dispatcher_ = MakeGarbageCollected<MIDIDispatcher>(GetExecutionContext());
dispatcher_->SetClient(this);
}
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 7ca6b29a6b4..8ef567a2397 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
@@ -24,7 +24,6 @@ class ScriptState;
class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver,
public MIDIDispatcher::Client {
- USING_PRE_FINALIZER(MIDIAccessInitializer, Dispose);
public:
struct PortDescriptor {
@@ -61,8 +60,6 @@ class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver,
MIDIAccessInitializer(ScriptState*, const MIDIOptions*);
~MIDIAccessInitializer() override = default;
- void Dispose();
-
// MIDIDispatcher::Client
void DidAddInputPort(const String& id,
const String& manufacturer,
@@ -97,7 +94,7 @@ class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver,
void OnPermissionsUpdated(mojom::blink::PermissionStatus);
void OnPermissionUpdated(mojom::blink::PermissionStatus);
- std::unique_ptr<MIDIDispatcher> dispatcher_;
+ Member<MIDIDispatcher> dispatcher_;
Vector<PortDescriptor> port_descriptors_;
Member<const MIDIOptions> options_;
diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
index a9aba08713c..cbc52a63f97 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.cc
@@ -7,9 +7,12 @@
#include <utility>
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.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_string.h"
+#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"
@@ -23,15 +26,20 @@ namespace {
static const size_t kMaxUnacknowledgedBytesSent = 10 * 1024 * 1024; // 10 MB.
} // namespace
-MIDIDispatcher::MIDIDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : task_runner_(std::move(task_runner)) {
+MIDIDispatcher::MIDIDispatcher(ExecutionContext* execution_context)
+ : midi_session_(execution_context),
+ receiver_(this, execution_context),
+ midi_session_provider_(execution_context) {
TRACE_EVENT0("midi", "MIDIDispatcher::MIDIDispatcher");
- Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
- midi_session_provider_.BindNewPipeAndPassReceiver(task_runner_));
+ // See https://bit.ly/2S0zRAS for task types.
+ execution_context->GetBrowserInterfaceBroker().GetInterface(
+ midi_session_provider_.BindNewPipeAndPassReceiver(
+ execution_context->GetTaskRunner(blink::TaskType::kMiscPlatformAPI)));
midi_session_provider_->StartSession(
- midi_session_.BindNewPipeAndPassReceiver(),
- receiver_.BindNewPipeAndPassRemote());
+ midi_session_.BindNewPipeAndPassReceiver(
+ execution_context->GetTaskRunner(blink::TaskType::kMiscPlatformAPI)),
+ receiver_.BindNewPipeAndPassRemote(
+ execution_context->GetTaskRunner(blink::TaskType::kMiscPlatformAPI)));
}
MIDIDispatcher::~MIDIDispatcher() = default;
@@ -129,4 +137,10 @@ void MIDIDispatcher::DataReceived(uint32_t port,
client_->DidReceiveMIDIData(port, &data[0], data.size(), timestamp);
}
+void MIDIDispatcher::Trace(Visitor* visitor) const {
+ visitor->Trace(midi_session_);
+ visitor->Trace(receiver_);
+ visitor->Trace(midi_session_provider_);
+}
+
} // 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
index f3bedca5534..a7d0eeecd25 100644
--- a/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h
+++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_dispatcher.h
@@ -6,14 +6,16 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_DISPATCHER_H_
#include "media/midi/midi_service.mojom-blink.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
-class MIDIDispatcher : public midi::mojom::blink::MidiSessionClient {
+class MIDIDispatcher : public GarbageCollected<MIDIDispatcher>,
+ public midi::mojom::blink::MidiSessionClient {
public:
class Client {
public:
@@ -39,8 +41,7 @@ class MIDIDispatcher : public midi::mojom::blink::MidiSessionClient {
base::TimeTicks time_stamp) = 0;
};
- explicit MIDIDispatcher(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ explicit MIDIDispatcher(ExecutionContext* execution_context);
~MIDIDispatcher() override;
void SetClient(Client* client) { client_ = client; }
@@ -64,6 +65,8 @@ class MIDIDispatcher : public midi::mojom::blink::MidiSessionClient {
const Vector<uint8_t>& data,
base::TimeTicks timestamp) override;
+ void Trace(Visitor* visitor) const;
+
private:
Client* client_ = nullptr;
@@ -76,12 +79,12 @@ class MIDIDispatcher : public midi::mojom::blink::MidiSessionClient {
// TODO(toyoshim): Consider to have a per-process limit.
size_t unacknowledged_bytes_sent_ = 0u;
- mojo::Remote<midi::mojom::blink::MidiSession> midi_session_;
-
- mojo::Receiver<midi::mojom::blink::MidiSessionClient> receiver_{this};
- mojo::Remote<midi::mojom::blink::MidiSessionProvider> midi_session_provider_;
+ HeapMojoRemote<midi::mojom::blink::MidiSession> midi_session_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ HeapMojoReceiver<midi::mojom::blink::MidiSessionClient, MIDIDispatcher>
+ receiver_;
+ HeapMojoRemote<midi::mojom::blink::MidiSessionProvider>
+ midi_session_provider_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webrtc/BUILD.gn b/chromium/third_party/blink/renderer/modules/webrtc/BUILD.gn
index 185bffa5102..c00e88a641c 100644
--- a/chromium/third_party/blink/renderer/modules/webrtc/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webrtc/BUILD.gn
@@ -15,4 +15,7 @@ blink_modules_sources("webrtc") {
]
deps = [ "//third_party/blink/renderer/modules/mediastream" ]
+
+ allow_circular_includes_from =
+ [ "//third_party/blink/renderer/modules/mediastream" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/webshare/FILE_TYPES.md b/chromium/third_party/blink/renderer/modules/webshare/FILE_TYPES.md
new file mode 100644
index 00000000000..0fa2dfb6403
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webshare/FILE_TYPES.md
@@ -0,0 +1,51 @@
+## Web Share - Permitted File Extensions in Chromium
+
+The following list should be kept in sync with
+- //chrome/browser/webshare/share_service_impl.cc
+- //components/browser_ui/webshare/android/java/src/org/chromium/components/browser_ui/webshare/ShareServiceImpl.java
+
+
+# Audio
+ "flac" - audio/flac
+ "m4a" - audio/x-m4a
+ "mp3" - audio/mp3
+ "oga" - audio/ogg
+ "ogg" - audio/ogg
+ "opus" - audio/ogg
+ "wav" - audio/wav
+ "weba" - audio/webm
+# Image
+ "bmp" - image/bmp
+ "gif" - image/gif
+ "ico" - image/x-icon
+ "jfif" - image/jpeg
+ "jpeg" - image/jpeg
+ "jpg" - image/jpeg
+ "pjp" - image/jpeg
+ "pjpeg" - image/jpeg
+ "png" - image/png
+ "svg" - image/svg+xml
+ "svgz" - image/svg+xml
+ "tif" - image/tiff
+ "tiff" - image/tiff
+ "webp" - image/webp
+ "xbm" - image/x-xbitmap
+# Text
+ "css" - text/css
+ "csv" - text/csv
+ "ehtml" - text/html
+ "htm" - text/html
+ "html" - text/html
+ "shtm" - text/html
+ "shtml" - text/html
+ "text" - text/plain
+ "txt" - text/plain
+# Video
+ "m4v" - video/mp4
+ "mp4" - video/mp4
+ "mpeg" - video/mpeg
+ "mpg" - video/mpeg
+ "ogm" - video/ogg
+ "ogv" - video/ogg
+ "webm" - video/webm
+
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 97a8615aa89..9d0bb564f47 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc
@@ -81,7 +81,9 @@ bool CanShareInternal(const LocalDOMWindow& window,
if (data.hasUrl()) {
url = window.CompleteURL(data.url());
- if (!url.IsValid()) {
+ if (!url.IsValid() ||
+ (!url.ProtocolIsInHTTPFamily() &&
+ url.Protocol() != window.document()->BaseURL().Protocol())) {
if (exception_state) {
exception_state->ThrowTypeError("Invalid URL");
}
@@ -131,8 +133,10 @@ NavigatorShare::ShareClientImpl::ShareClientImpl(
{SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
void NavigatorShare::ShareClientImpl::Callback(mojom::blink::ShareError error) {
- if (navigator_)
- navigator_->clients_.erase(this);
+ if (navigator_) {
+ DCHECK_EQ(navigator_->client_, this);
+ navigator_->client_ = nullptr;
+ }
if (error == mojom::blink::ShareError::OK) {
UseCounter::Count(ExecutionContext::From(resolver_->GetScriptState()),
@@ -171,7 +175,7 @@ NavigatorShare& NavigatorShare::From(Navigator& navigator) {
void NavigatorShare::Trace(Visitor* visitor) const {
visitor->Trace(service_remote_);
- visitor->Trace(clients_);
+ visitor->Trace(client_);
Supplement<Navigator>::Trace(visitor);
}
@@ -211,6 +215,12 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
? WebFeature::kWebSharePolicyAllow
: WebFeature::kWebSharePolicyDisallow);
+ if (client_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "A earlier share had not yet completed.");
+ return ScriptPromise();
+ }
+
if (!LocalFrame::ConsumeTransientUserActivation(window->GetFrame())) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotAllowedError,
@@ -236,10 +246,7 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
bool has_files = HasFiles(*data);
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- ShareClientImpl* client =
- MakeGarbageCollected<ShareClientImpl>(this, has_files, resolver);
- clients_.insert(client);
- ScriptPromise promise = resolver->Promise();
+ client_ = MakeGarbageCollected<ShareClientImpl>(this, has_files, resolver);
WTF::Vector<mojom::blink::SharedFilePtr> files;
uint64_t total_bytes = 0;
@@ -262,9 +269,9 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
service_remote_->Share(
data->hasTitle() ? data->title() : g_empty_string,
data->hasText() ? data->text() : g_empty_string, url, std::move(files),
- WTF::Bind(&ShareClientImpl::Callback, WrapPersistent(client)));
+ WTF::Bind(&ShareClientImpl::Callback, WrapPersistent(client_.Get())));
- return promise;
+ return resolver->Promise();
}
ScriptPromise NavigatorShare::share(ScriptState* script_state,
@@ -275,10 +282,10 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state,
}
void NavigatorShare::OnConnectionError() {
- for (auto& client : clients_) {
- client->OnConnectionError();
+ if (client_) {
+ client_->OnConnectionError();
+ client_ = nullptr;
}
- clients_.clear();
service_remote_.reset();
}
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 f77d235b4b9..be5fe4ccc37 100644
--- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h
+++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.h
@@ -56,7 +56,8 @@ class MODULES_EXPORT NavigatorShare final
// |NavigatorShare| is not ExecutionContext-associated.
HeapMojoRemote<blink::mojom::blink::ShareService> service_remote_{nullptr};
- HeapHashSet<Member<ShareClientImpl>> clients_;
+ // Represents a user's current intent to share some data.
+ Member<ShareClientImpl> client_ = nullptr;
};
} // namespace blink
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 006263c4b46..e4aa818faaf 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -73,9 +73,6 @@
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
-static const size_t kMaxByteSizeForHistogram = 100 * 1000 * 1000;
-static const int32_t kBucketCountForMessageSizeHistogram = 50;
-
namespace blink {
DOMWebSocket::EventQueue::EventQueue(EventTarget* target)
@@ -357,8 +354,6 @@ void DOMWebSocket::send(DOMArrayBuffer* binary_data,
return;
}
RecordSendTypeHistogram(WebSocketSendType::kArrayBuffer);
- RecordSendMessageSizeHistogram(WebSocketSendType::kArrayBuffer,
- binary_data->ByteLengthAsSizeT());
DCHECK(channel_);
buffered_amount_ += binary_data->ByteLengthAsSizeT();
channel_->Send(*binary_data, 0, binary_data->ByteLengthAsSizeT(),
@@ -380,8 +375,6 @@ void DOMWebSocket::send(NotShared<DOMArrayBufferView> array_buffer_view,
return;
}
RecordSendTypeHistogram(WebSocketSendType::kArrayBufferView);
- RecordSendMessageSizeHistogram(WebSocketSendType::kArrayBufferView,
- array_buffer_view.View()->byteLengthAsSizeT());
DCHECK(channel_);
buffered_amount_ += array_buffer_view.View()->byteLengthAsSizeT();
channel_->Send(*array_buffer_view.View()->buffer(),
@@ -404,9 +397,6 @@ void DOMWebSocket::send(Blob* binary_data, ExceptionState& exception_state) {
}
uint64_t size = binary_data->size();
RecordSendTypeHistogram(WebSocketSendType::kBlob);
- RecordSendMessageSizeHistogram(
- WebSocketSendType::kBlob,
- clampTo<size_t>(size, 0, kMaxByteSizeForHistogram));
buffered_amount_ += size;
DCHECK(channel_);
@@ -569,15 +559,12 @@ void DOMWebSocket::DidReceiveBinaryMessage(
}
auto* blob = MakeGarbageCollected<Blob>(
BlobDataHandle::Create(std::move(blob_data), size));
- RecordReceiveMessageSizeHistogram(WebSocketReceiveType::kBlob, size);
event_queue_->Dispatch(MessageEvent::Create(blob, origin_string_));
break;
}
case kBinaryTypeArrayBuffer:
DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(data);
- RecordReceiveMessageSizeHistogram(WebSocketReceiveType::kArrayBuffer,
- size);
event_queue_->Dispatch(
MessageEvent::Create(array_buffer, origin_string_));
break;
@@ -633,60 +620,6 @@ void DOMWebSocket::RecordSendTypeHistogram(WebSocketSendType type) {
base::UmaHistogramEnumeration("WebCore.WebSocket.SendType", type);
}
-void DOMWebSocket::RecordSendMessageSizeHistogram(WebSocketSendType type,
- size_t size) {
- // Truncate |size| to avoid overflowing int32_t.
- int32_t size_to_count = clampTo<int32_t>(size, 0, kMaxByteSizeForHistogram);
- switch (type) {
- case WebSocketSendType::kArrayBuffer:
- base::UmaHistogramCustomCounts(
- "WebCore.WebSocket.MessageSize.Send.ArrayBuffer", size_to_count, 1,
- kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
- return;
-
- case WebSocketSendType::kArrayBufferView:
- base::UmaHistogramCustomCounts(
- "WebCore.WebSocket.MessageSize.Send.ArrayBufferView", size_to_count,
- 1, kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
- return;
-
- case WebSocketSendType::kBlob:
- base::UmaHistogramCustomCounts("WebCore.WebSocket.MessageSize.Send.Blob",
- size_to_count, 1, kMaxByteSizeForHistogram,
- kBucketCountForMessageSizeHistogram);
- return;
-
- case WebSocketSendType::kString:
- NOTREACHED();
- return;
- }
- NOTREACHED();
-}
-
-void DOMWebSocket::RecordReceiveMessageSizeHistogram(WebSocketReceiveType type,
- size_t size) {
- // Truncate |size| to avoid overflowing int32_t.
- int32_t size_to_count = clampTo<int32_t>(size, 0, kMaxByteSizeForHistogram);
- switch (type) {
- case WebSocketReceiveType::kArrayBuffer:
- base::UmaHistogramCustomCounts(
- "WebCore.WebSocket.MessageSize.Receive.ArrayBuffer", size_to_count, 1,
- kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
- return;
-
- case WebSocketReceiveType::kBlob:
- base::UmaHistogramCustomCounts(
- "WebCore.WebSocket.MessageSize.Receive.Blob", size_to_count, 1,
- kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
- return;
-
- case WebSocketReceiveType::kString:
- NOTREACHED();
- return;
- }
- NOTREACHED();
-}
-
void DOMWebSocket::Trace(Visitor* visitor) const {
visitor->Trace(channel_);
visitor->Trace(event_queue_);
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 fb8a93759c1..883b63d0021 100644
--- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h
+++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h
@@ -202,13 +202,6 @@ class MODULES_EXPORT DOMWebSocket
kMaxValue = kBlob,
};
- enum class WebSocketReceiveType {
- kString,
- kArrayBuffer,
- kBlob,
- kMaxValue = kBlob,
- };
-
enum BinaryType { kBinaryTypeBlob, kBinaryTypeArrayBuffer };
// This function is virtual for unittests.
@@ -244,8 +237,6 @@ class MODULES_EXPORT DOMWebSocket
void ReleaseChannel();
void RecordSendTypeHistogram(WebSocketSendType);
- void RecordSendMessageSizeHistogram(WebSocketSendType, size_t);
- void RecordReceiveMessageSizeHistogram(WebSocketReceiveType, size_t);
Member<WebSocketChannel> channel_;
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 3c99d67b0e8..a04a76dab1e 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
@@ -35,6 +35,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/feature_list.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/util/type_safety/strong_alias.h"
@@ -81,6 +82,17 @@ enum WebSocketOpCode {
kOpCodeBinary = 0x2,
};
+// When enabled, a page can be aggressively throttled even if it uses a
+// WebSocket. Aggressive throttling does not affect the execution of WebSocket
+// event handlers, so there is little reason to disable it on pages using a
+// WebSocket.
+//
+// TODO(crbug.com/1121725): Cleanup this feature once field experiments confirm
+// that the opt-out can be removed.
+const base::Feature kAllowAggressiveThrottlingWithWebSocket{
+ "AllowAggressiveThrottlingWithWebSocket",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace
class WebSocketChannelImpl::BlobLoader final
@@ -205,8 +217,12 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
if (auto* scheduler = execution_context_->GetScheduler()) {
feature_handle_for_scheduler_ = scheduler->RegisterFeature(
SchedulingPolicy::Feature::kWebSocket,
- {SchedulingPolicy::DisableAggressiveThrottling(),
- SchedulingPolicy::RecordMetricsForBackForwardCache()});
+ base::FeatureList::IsEnabled(kAllowAggressiveThrottlingWithWebSocket)
+ ? SchedulingPolicy{SchedulingPolicy::
+ RecordMetricsForBackForwardCache()}
+ : SchedulingPolicy{
+ SchedulingPolicy::DisableAggressiveThrottling(),
+ SchedulingPolicy::RecordMetricsForBackForwardCache()});
}
if (MixedContentChecker::IsMixedContent(
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/BUILD.gn b/chromium/third_party/blink/renderer/modules/webtransport/BUILD.gn
index 03f771f7357..4072c3bcc2a 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/webtransport/BUILD.gn
@@ -18,6 +18,8 @@ blink_modules_sources("webtransport") {
"receive_stream.h",
"send_stream.cc",
"send_stream.h",
+ "web_transport.cc",
+ "web_transport.h",
"web_transport_stream.h",
]
}
@@ -40,10 +42,13 @@ source_set("unit_tests") {
]
deps = [
+ "//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//third_party/blink/renderer/controller:blink_bindings_test_sources",
"//third_party/blink/renderer/modules",
"//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform:test_support",
"//third_party/blink/renderer/platform/wtf",
]
}
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.cc b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.cc
index fa602811644..e716d36d949 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.cc
@@ -39,11 +39,12 @@ void BidirectionalStream::Init() {
void BidirectionalStream::OnIncomingStreamClosed(bool fin_received) {
incoming_stream_->OnIncomingStreamClosed(fin_received);
- // TODO(ricea): Review this behaviour when adding detail to the specification.
- if (!sent_fin_) {
- ScriptState::Scope scope(outgoing_stream_->GetScriptState());
- outgoing_stream_->Reset();
+ if (outgoing_stream_->GetState() == OutgoingStream::State::kSentFin) {
+ return;
}
+
+ ScriptState::Scope scope(outgoing_stream_->GetScriptState());
+ outgoing_stream_->Reset();
}
void BidirectionalStream::Reset() {
@@ -59,15 +60,15 @@ void BidirectionalStream::ContextDestroyed() {
void BidirectionalStream::SendFin() {
quic_transport_->SendFin(stream_id_);
- sent_fin_ = true;
// The IncomingStream will be closed on the network service side.
}
void BidirectionalStream::OnOutgoingStreamAbort() {
- DCHECK(!sent_fin_);
quic_transport_->AbortStream(stream_id_);
quic_transport_->ForgetStream(stream_id_);
- incoming_stream_->Reset();
+ if (incoming_stream_->GetState() == IncomingStream::State::kOpen) {
+ incoming_stream_->Reset();
+ }
}
void BidirectionalStream::Trace(Visitor* visitor) const {
@@ -81,6 +82,9 @@ void BidirectionalStream::Trace(Visitor* visitor) const {
void BidirectionalStream::OnIncomingStreamAbort() {
quic_transport_->ForgetStream(stream_id_);
+ if (outgoing_stream_->GetState() == OutgoingStream::State::kAborted) {
+ return;
+ }
ScriptState::Scope scope(outgoing_stream_->GetScriptState());
outgoing_stream_->Reset();
}
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.h b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.h
index 1fcef34e8bf..1e1663a90c2 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream.h
@@ -77,7 +77,6 @@ class MODULES_EXPORT BidirectionalStream final : public ScriptWrappable,
const Member<IncomingStream> incoming_stream_;
const Member<QuicTransport> quic_transport_;
const uint32_t stream_id_;
- bool sent_fin_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc
index 088b21cb1fb..744fd9a2f6e 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/bidirectional_stream_test.cc
@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_uint8_array.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_bidirectional_stream.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_quic_transport_options.h"
@@ -380,6 +381,25 @@ TEST(BidirectionalStreamTest, IncomingStreamCleanClose) {
kDefaultStreamId, true);
scoped_quic_transport.Stub()->InputProducer().reset();
+ auto* script_state = scope.GetScriptState();
+ auto* reader = bidirectional_stream->readable()->getReader(
+ script_state, ASSERT_NO_EXCEPTION);
+
+ ScriptPromise read_promise = reader->read(script_state, ASSERT_NO_EXCEPTION);
+
+ ScriptPromiseTester read_tester(script_state, read_promise);
+ read_tester.WaitUntilSettled();
+ EXPECT_TRUE(read_tester.IsFulfilled());
+
+ v8::Local<v8::Value> result = read_tester.Value().V8Value();
+ DCHECK(result->IsObject());
+ v8::Local<v8::Value> v8value;
+ bool done = false;
+ EXPECT_TRUE(
+ V8UnpackIteratorResult(script_state, result.As<v8::Object>(), &done)
+ .ToLocal(&v8value));
+ EXPECT_TRUE(done);
+
ScriptPromiseTester tester(scope.GetScriptState(),
bidirectional_stream->writingAborted());
tester.WaitUntilSettled();
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/idls.gni b/chromium/third_party/blink/renderer/modules/webtransport/idls.gni
index 3c8d7386e48..a39dfd30bcc 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/webtransport/idls.gni
@@ -7,6 +7,7 @@ modules_idl_files = [
"quic_transport.idl",
"receive_stream.idl",
"send_stream.idl",
+ "web_transport.idl",
]
modules_dictionary_idl_files = [
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc
index 4bc95913eb5..997fa916de4 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.cc
@@ -105,6 +105,9 @@ void IncomingStream::OnIncomingStreamClosed(bool fin_received) {
DVLOG(1) << "IncomingStream::OnIncomingStreamClosed(" << fin_received
<< ") this=" << this;
+ DCHECK_NE(state_, State::kClosed);
+ state_ = State::kClosed;
+
DCHECK(!fin_received_.has_value());
fin_received_ = fin_received;
@@ -314,6 +317,8 @@ void IncomingStream::AbortAndReset() {
reading_aborted_resolver_ = nullptr;
}
+ state_ = State::kAborted;
+
if (on_abort_) {
// Cause QuicTransport to drop its reference to us.
std::move(on_abort_).Run();
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h
index dd529b70e8f..b83a684f761 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/incoming_stream.h
@@ -35,6 +35,12 @@ class MODULES_EXPORT IncomingStream final
USING_PRE_FINALIZER(IncomingStream, Dispose);
public:
+ enum class State {
+ kOpen,
+ kAborted,
+ kClosed,
+ };
+
IncomingStream(ScriptState*,
base::OnceClosure on_abort,
mojo::ScopedDataPipeConsumerHandle);
@@ -68,6 +74,8 @@ class MODULES_EXPORT IncomingStream final
// Does not execute JavaScript.
void ContextDestroyed();
+ State GetState() const { return state_; }
+
void Trace(Visitor*) const;
private:
@@ -136,6 +144,8 @@ class MODULES_EXPORT IncomingStream final
ScriptPromise reading_aborted_;
Member<ScriptPromiseResolver> reading_aborted_resolver_;
+ State state_ = State::kOpen;
+
// This is set when OnIncomingStreamClosed() is called.
base::Optional<bool> fin_received_;
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc
index 61bba5dc127..63548a26876 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.cc
@@ -66,6 +66,7 @@ class OutgoingStream::UnderlyingSink final : public UnderlyingSinkBase {
DCHECK(!outgoing_stream_->write_promise_resolver_);
if (outgoing_stream_->client_) {
+ outgoing_stream_->state_ = State::kSentFin;
outgoing_stream_->client_->SendFin();
outgoing_stream_->client_ = nullptr;
}
@@ -389,6 +390,8 @@ void OutgoingStream::AbortAndReset() {
}
if (client_) {
+ DCHECK_EQ(state_, State::kOpen);
+ state_ = State::kAborted;
client_->OnOutgoingStreamAbort();
client_ = nullptr;
}
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h
index d24b2d5311c..73ff45a6bf7 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/outgoing_stream.h
@@ -52,6 +52,12 @@ class MODULES_EXPORT OutgoingStream final
virtual void OnOutgoingStreamAbort() = 0;
};
+ enum class State {
+ kOpen,
+ kSentFin,
+ kAborted,
+ };
+
OutgoingStream(ScriptState*, Client*, mojo::ScopedDataPipeProducerHandle);
~OutgoingStream();
@@ -76,6 +82,8 @@ class MODULES_EXPORT OutgoingStream final
// scope to be entered.
void Reset();
+ State GetState() const { return state_; }
+
// Called from QuicTransport rather than using
// ExecutionContextLifecycleObserver to ensure correct destruction order.
// Does not execute JavaScript.
@@ -180,6 +188,8 @@ class MODULES_EXPORT OutgoingStream final
// If an asynchronous write() on the underlying sink object is pending, this
// will be non-null.
Member<ScriptPromiseResolver> write_promise_resolver_;
+
+ State state_ = State::kOpen;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc
index eec17682573..6d565193229 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.cc
@@ -21,6 +21,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_dtls_fingerprint.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/web_feature.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
@@ -347,6 +348,7 @@ QuicTransport* QuicTransport::Create(ScriptState* script_state,
ExceptionState& exception_state) {
DVLOG(1) << "QuicTransport::Create() url=" << url;
DCHECK(options);
+ ExecutionContext::From(script_state)->CountUse(WebFeature::kQuicTransport);
auto* transport =
MakeGarbageCollected<QuicTransport>(PassKey(), script_state, url);
transport->Init(url, *options, exception_state);
@@ -372,6 +374,7 @@ ScriptPromise QuicTransport::createSendStream(ScriptState* script_state,
ExceptionState& exception_state) {
DVLOG(1) << "QuicTransport::createSendStream() this=" << this;
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportStreamApis);
if (!quic_transport_.is_bound()) {
// TODO(ricea): Should we wait if we're still connecting?
exception_state.ThrowDOMException(DOMExceptionCode::kNetworkError,
@@ -398,11 +401,17 @@ ScriptPromise QuicTransport::createSendStream(ScriptState* script_state,
return resolver->Promise();
}
+ReadableStream* QuicTransport::receiveStreams() {
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportStreamApis);
+ return received_streams_;
+}
+
ScriptPromise QuicTransport::createBidirectionalStream(
ScriptState* script_state,
ExceptionState& exception_state) {
DVLOG(1) << "QuicTransport::createBidirectionalStream() this=" << this;
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportStreamApis);
if (!quic_transport_.is_bound()) {
// TODO(ricea): We should wait if we are still connecting.
exception_state.ThrowDOMException(DOMExceptionCode::kNetworkError,
@@ -442,6 +451,21 @@ ScriptPromise QuicTransport::createBidirectionalStream(
return resolver->Promise();
}
+ReadableStream* QuicTransport::receiveBidirectionalStreams() {
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportStreamApis);
+ return received_bidirectional_streams_;
+}
+
+WritableStream* QuicTransport::sendDatagrams() {
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportDatagramApis);
+ return outgoing_datagrams_;
+}
+
+ReadableStream* QuicTransport::receiveDatagrams() {
+ GetExecutionContext()->CountUse(WebFeature::kQuicTransportDatagramApis);
+ return received_datagrams_;
+}
+
void QuicTransport::close(const WebTransportCloseInfo* close_info) {
DVLOG(1) << "QuicTransport::close() this=" << this;
// TODO(ricea): Send |close_info| to the network service.
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h
index 540c5d75274..2bcfefa32d5 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.h
@@ -60,15 +60,13 @@ class MODULES_EXPORT QuicTransport final
// QuicTransport IDL implementation.
ScriptPromise createSendStream(ScriptState*, ExceptionState&);
- ReadableStream* receiveStreams() { return received_streams_; }
+ ReadableStream* receiveStreams();
ScriptPromise createBidirectionalStream(ScriptState*, ExceptionState&);
- ReadableStream* receiveBidirectionalStreams() {
- return received_bidirectional_streams_;
- }
+ ReadableStream* receiveBidirectionalStreams();
- WritableStream* sendDatagrams() { return outgoing_datagrams_; }
- ReadableStream* receiveDatagrams() { return received_datagrams_; }
+ WritableStream* sendDatagrams();
+ ReadableStream* receiveDatagrams();
void close(const WebTransportCloseInfo*);
ScriptPromise ready() { return ready_; }
ScriptPromise closed() { return closed_; }
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.idl b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.idl
index 56aca2a3ee5..a45c915a0e4 100644
--- a/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.idl
+++ b/chromium/third_party/blink/renderer/modules/webtransport/quic_transport.idl
@@ -8,27 +8,27 @@
Exposed=(Window,Worker),
RuntimeEnabled=QuicTransport
] interface QuicTransport {
- [CallWith=ScriptState, RaisesException, MeasureAs=QuicTransport] constructor(USVString url, optional QuicTransportOptions options = {});
+ [CallWith=ScriptState, RaisesException] constructor(USVString url, optional QuicTransportOptions options = {});
// QuicTransport is the first, and at this moment only, transport which is
// implemented. In the (draft) spec there are many mix-in interfaces which
// QuicTransport includes, but we define all their methods/attributes here
// for simplicity.
// From UnidirectionalStreamsTransport
- [CallWith=ScriptState, RaisesException, MeasureAs=QuicTransportStreamApis] Promise<SendStream>
+ [CallWith=ScriptState, RaisesException] Promise<SendStream>
createSendStream();
// TODO(ricea): This should probably be changed to an attribute in the
// standard.
- [MeasureAs=QuicTransportStreamApis] ReadableStream receiveStreams();
+ ReadableStream receiveStreams();
// From BidirectionalStreamsTransport
- [CallWith=ScriptState, RaisesException, MeasureAs=QuicTransportStreamApis] Promise<BidirectionalStream>
+ [CallWith=ScriptState, RaisesException] Promise<BidirectionalStream>
createBidirectionalStream();
- [MeasureAs=QuicTransportStreamApis] ReadableStream receiveBidirectionalStreams();
+ ReadableStream receiveBidirectionalStreams();
// From DatagramTransport mixin
- [MeasureAs=QuicTransportDatagramApis] WritableStream sendDatagrams();
- [MeasureAs=QuicTransportDatagramApis] ReadableStream receiveDatagrams();
+ WritableStream sendDatagrams();
+ ReadableStream receiveDatagrams();
// From WebTransport mixin
void close(optional WebTransportCloseInfo closeInfo = {});
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.cc b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.cc
new file mode 100644
index 00000000000..98f25a3d8f4
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webtransport/web_transport.h"
+
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+WebTransport::WebTransport(PassKey, QuicTransport* quic_transport)
+ : quic_transport_(quic_transport) {}
+WebTransport::~WebTransport() = default;
+
+WebTransport* WebTransport::Create(ScriptState* script_state,
+ const String& url,
+ QuicTransportOptions* options,
+ ExceptionState& exception_state) {
+ QuicTransport* quic_transport =
+ QuicTransport::Create(script_state, url, options, exception_state);
+ if (exception_state.HadException()) {
+ return nullptr;
+ }
+ return MakeGarbageCollected<WebTransport>(PassKey(), quic_transport);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h
new file mode 100644
index 00000000000..12e0ec0accf
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.h
@@ -0,0 +1,83 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_WEB_TRANSPORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_WEB_TRANSPORT_H_
+
+#include "base/util/type_safety/pass_key.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/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webtransport/quic_transport.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+
+namespace blink {
+
+class ScriptState;
+
+class MODULES_EXPORT WebTransport final
+ : public ScriptWrappable,
+ public ActiveScriptWrappable<WebTransport> {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ using PassKey = util::PassKey<WebTransport>;
+ static WebTransport* Create(ScriptState*,
+ const String& url,
+ QuicTransportOptions*,
+ ExceptionState&);
+
+ WebTransport(PassKey, QuicTransport*);
+ ~WebTransport() override;
+
+ // WebTransport IDL implementation.
+ ScriptPromise createUnidirectionalStream(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ return quic_transport_->createSendStream(script_state, exception_state);
+ }
+ ReadableStream* incomingUnidirectionalStreams() {
+ return quic_transport_->receiveStreams();
+ }
+
+ ScriptPromise createBidirectionalStream(ScriptState* script_state,
+ ExceptionState& exception_state) {
+ return quic_transport_->createBidirectionalStream(script_state,
+ exception_state);
+ }
+ ReadableStream* incomingBidirectionalStreams() {
+ return quic_transport_->receiveBidirectionalStreams();
+ }
+ WritableStream* datagramWritable() {
+ return quic_transport_->sendDatagrams();
+ }
+ ReadableStream* datagramReadable() {
+ return quic_transport_->receiveDatagrams();
+ }
+ void close(const WebTransportCloseInfo* close_info) {
+ quic_transport_->close(close_info);
+ }
+ ScriptPromise ready() { return quic_transport_->ready(); }
+ ScriptPromise closed() { return quic_transport_->closed(); }
+
+ bool HasPendingActivity() const override {
+ return quic_transport_->HasPendingActivity();
+ }
+
+ void Trace(Visitor* visitor) const override {
+ visitor->Trace(quic_transport_);
+ ScriptWrappable::Trace(visitor);
+ }
+
+ ExecutionContext* GetExecutionContext() const {
+ return quic_transport_->GetExecutionContext();
+ }
+
+ private:
+ const Member<QuicTransport> quic_transport_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_WEB_TRANSPORT_H_
diff --git a/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl
new file mode 100644
index 00000000000..16df63a2e0f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/webtransport/web_transport.idl
@@ -0,0 +1,26 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/web-transport/#web-transport
+[
+ ActiveScriptWrappable,
+ Exposed=(Window,Worker),
+ RuntimeEnabled=QuicTransport
+] interface WebTransport {
+ [CallWith=ScriptState, RaisesException, MeasureAs=WebTransport] constructor(USVString url, optional QuicTransportOptions options = {});
+ [CallWith=ScriptState, RaisesException] Promise<SendStream>
+ createUnidirectionalStream();
+ readonly attribute ReadableStream incomingUnidirectionalStreams;
+
+ [CallWith=ScriptState, RaisesException] Promise<BidirectionalStream>
+ createBidirectionalStream();
+ readonly attribute ReadableStream incomingBidirectionalStreams;
+
+ readonly attribute WritableStream datagramWritable;
+ readonly attribute ReadableStream datagramReadable;
+
+ void close(optional WebTransportCloseInfo closeInfo = {});
+ readonly attribute Promise<void> ready;
+ readonly attribute Promise<WebTransportCloseInfo> closed;
+};
diff --git a/chromium/third_party/blink/renderer/modules/worklet/BUILD.gn b/chromium/third_party/blink/renderer/modules/worklet/BUILD.gn
index fb7b2fe7667..17481b94223 100644
--- a/chromium/third_party/blink/renderer/modules/worklet/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/worklet/BUILD.gn
@@ -13,4 +13,8 @@ blink_modules_sources("worklet") {
"//third_party/blink/renderer/modules/animationworklet",
"//third_party/blink/renderer/modules/csspaint",
]
+ allow_circular_includes_from = [
+ "//third_party/blink/renderer/modules/animationworklet",
+ "//third_party/blink/renderer/modules/csspaint:csspaint",
+ ]
}
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 658dd80ce63..e4bfb7de62d 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
@@ -81,8 +81,9 @@ class AnimationAndPaintWorkletThreadTest : public PageTestBase {
ScriptValue exception =
ModuleRecord::Instantiate(script_state, module, js_url);
EXPECT_TRUE(exception.IsEmpty());
- EXPECT_TRUE(
- ModuleRecord::Evaluate(script_state, module, js_url).IsSuccess());
+ EXPECT_EQ(
+ ModuleRecord::Evaluate(script_state, module, js_url).GetResultType(),
+ ScriptEvaluationResult::ResultType::kSuccess);
wait_event->Signal();
}
};
diff --git a/chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc b/chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
index 667c448d5b5..4aa6a6fab8d 100644
--- a/chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
+++ b/chromium/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
@@ -38,7 +38,7 @@ CreateAnimationAndPaintWorkletThread(
nullptr /* content_settings_client */, window->AddressSpace(),
OriginTrialContext::GetTokens(window).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
- kV8CacheOptionsDefault,
+ mojom::blink::V8CacheOptions::kDefault,
MakeGarbageCollected<WorkletModuleResponsesMap>(),
mojo::NullRemote() /* browser_interface_broker */,
BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
diff --git a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
index e6144d5c90a..c933239ebd7 100644
--- a/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
+++ b/chromium/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -21,6 +21,8 @@ blink_modules_sources("xr") {
"xr_canvas_input_provider.h",
"xr_cube_map.cc",
"xr_cube_map.h",
+ "xr_depth_information.cc",
+ "xr_depth_information.h",
"xr_dom_overlay_state.cc",
"xr_dom_overlay_state.h",
"xr_frame.cc",
@@ -107,4 +109,6 @@ blink_modules_sources("xr") {
"//device/vr/public/mojom:mojom_blink",
"//services/metrics/public/cpp:ukm_builders",
]
+
+ public_deps = [ "//third_party/blink/renderer/modules/gamepad:gamepad" ]
}
diff --git a/chromium/third_party/blink/renderer/modules/xr/DEPS b/chromium/third_party/blink/renderer/modules/xr/DEPS
index 9d573fe4cff..f3b0e4eab08 100644
--- a/chromium/third_party/blink/renderer/modules/xr/DEPS
+++ b/chromium/third_party/blink/renderer/modules/xr/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+mojo/public/cpp/system/platform_handle.h",
"+device/vr/public/mojom/pose.h",
+ "+device/vr/public/mojom/rgba_tuple_f16.h",
"+device/vr/public/mojom/vr_service.mojom-blink.h",
"+device/vr/public/mojom/vr_service.mojom-blink-forward.h",
"+gpu/command_buffer/client/gles2_interface.h",
@@ -8,4 +9,5 @@ include_rules = [
"+services/metrics/public/cpp/ukm_builders.h",
"+ui/display/display.h",
"+ui/gfx/geometry",
+ "+ui/gfx/transform.h",
]
diff --git a/chromium/third_party/blink/renderer/modules/xr/idls.gni b/chromium/third_party/blink/renderer/modules/xr/idls.gni
index 50897f7d242..0346ec6f457 100644
--- a/chromium/third_party/blink/renderer/modules/xr/idls.gni
+++ b/chromium/third_party/blink/renderer/modules/xr/idls.gni
@@ -8,6 +8,7 @@ modules_idl_files = [
"xr_anchor.idl",
"xr_anchor_set.idl",
"xr_bounded_reference_space.idl",
+ "xr_depth_information.idl",
"xr_dom_overlay_state.idl",
"xr_frame.idl",
"xr_input_source.idl",
diff --git a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc
index 622e37b4c9c..781c90ba479 100644
--- a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.cc
@@ -17,6 +17,14 @@ namespace blink {
const char NavigatorXR::kSupplementName[] = "NavigatorXR";
+bool NavigatorXR::AlreadyExists(Document& document) {
+ if (!document.GetFrame())
+ return false;
+
+ Navigator& navigator = *document.GetFrame()->DomWindow()->navigator();
+ return !!Supplement<Navigator>::From<NavigatorXR>(navigator);
+}
+
NavigatorXR* NavigatorXR::From(Document& document) {
if (!document.GetFrame())
return nullptr;
diff --git a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h
index d35750293e1..26650eca882 100644
--- a/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h
+++ b/chromium/third_party/blink/renderer/modules/xr/navigator_xr.h
@@ -23,6 +23,10 @@ class MODULES_EXPORT NavigatorXR final : public GarbageCollected<NavigatorXR>,
static NavigatorXR* From(Document&);
static NavigatorXR& From(Navigator&);
+ // Allows us to check whether |Document| has a NavigatorXR, without triggering
+ // its lazy creation.
+ static bool AlreadyExists(Document&);
+
explicit NavigatorXR(Navigator&);
static XRSystem* xr(Navigator&);
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h
index 92f3dbe87c5..10c1c439794 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_anchor.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/optional.h"
+#include "device/vr/public/mojom/pose.h"
#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
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 431f6e4ae42..ffd5be1dbac 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
@@ -114,8 +114,8 @@ void XRCanvasInputProvider::UpdateInputSource(PointerEvent* event) {
// position of the screen interaction and shoves it backwards through the
// projection matrix to get a 3D point in space, which is then returned in
// matrix form so we can use it as an XRInputSource's pointerMatrix.
- XRViewData& view = session_->views()[0];
- TransformationMatrix viewer_from_pointer = view.UnprojectPointer(
+ XRViewData* view = session_->views()[0];
+ TransformationMatrix viewer_from_pointer = view->UnprojectPointer(
element_x, element_y, canvas_->OffsetWidth(), canvas_->OffsetHeight());
// Update the pointer pose in input space. For screen tapping, input
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h
index d31d42f1024..84c177c6e2e 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_cube_map.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_CUBE_MAP_H_
#include "base/util/type_safety/pass_key.h"
+#include "device/vr/public/mojom/rgba_tuple_f16.h"
#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc
new file mode 100644
index 00000000000..35f28c73a87
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.cc
@@ -0,0 +1,93 @@
+// Copyright 2020 The Chromium Authors. 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_depth_information.h"
+
+#include <cstdlib>
+
+#include "base/numerics/checked_math.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+namespace {
+constexpr char kOutOfBoundsAccess[] =
+ "Attempted to access data that is out-of-bounds.";
+}
+
+namespace blink {
+
+XRDepthInformation::XRDepthInformation(
+ const device::mojom::blink::XRDepthDataUpdated& depth_data)
+ : width_(depth_data.size.width()),
+ height_(depth_data.size.height()),
+ norm_texture_from_norm_view_(depth_data.norm_texture_from_norm_view) {
+ DVLOG(3) << __func__ << ": width_=" << width_ << ", height_=" << height_
+ << ", norm_texture_from_norm_view_="
+ << norm_texture_from_norm_view_.ToString();
+
+ CHECK_EQ(base::CheckMul(2, width_, height_).ValueOrDie(),
+ depth_data.pixel_data.size());
+
+ base::span<const uint16_t> pixel_data = base::make_span(
+ reinterpret_cast<const uint16_t*>(depth_data.pixel_data.data()),
+ depth_data.pixel_data.size() / 2);
+
+ // Copy the underlying pixel data into DOMUint16Array:
+ data_ = DOMUint16Array::Create(pixel_data.data(), pixel_data.size());
+}
+
+DOMUint16Array* XRDepthInformation::data() const {
+ return data_;
+}
+
+uint32_t XRDepthInformation::width() const {
+ return width_;
+}
+
+uint32_t XRDepthInformation::height() const {
+ return height_;
+}
+
+float XRDepthInformation::getDepth(uint32_t column,
+ uint32_t row,
+ ExceptionState& exception_state) const {
+ DVLOG(3) << __func__ << ": column=" << column << ", row=" << row;
+
+ if (column >= width_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
+ kOutOfBoundsAccess);
+ return 0.0;
+ }
+
+ if (row >= height_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError,
+ kOutOfBoundsAccess);
+ return 0.0;
+ }
+
+ auto checked_index = base::CheckAdd(column, base::CheckMul(row, width_));
+ size_t index = checked_index.ValueOrDie();
+
+ // Data is stored in millimeters, convert to meters when accessing:
+ float result = data_->Item(index) / 1000.0;
+
+ DVLOG(3) << __func__ << ": index=" << index << ", result=" << result;
+
+ return result;
+}
+
+XRRigidTransform* XRDepthInformation::normTextureFromNormView() const {
+ return MakeGarbageCollected<XRRigidTransform>(
+ TransformationMatrix(norm_texture_from_norm_view_.matrix()));
+}
+
+void XRDepthInformation::Trace(Visitor* visitor) const {
+ visitor->Trace(data_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h
new file mode 100644
index 00000000000..0245b1d54f9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_INFORMATION_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_INFORMATION_H_
+
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.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/wtf/forward.h"
+#include "ui/gfx/transform.h"
+
+namespace blink {
+
+class ExceptionState;
+class XRRigidTransform;
+
+class XRDepthInformation final : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ explicit XRDepthInformation(
+ const device::mojom::blink::XRDepthDataUpdated& depth_data);
+
+ DOMUint16Array* data() const;
+
+ uint32_t width() const;
+
+ uint32_t height() const;
+
+ XRRigidTransform* normTextureFromNormView() const;
+
+ float getDepth(uint32_t column,
+ uint32_t row,
+ ExceptionState& exception_state) const;
+
+ void Trace(Visitor* visitor) const override;
+
+ private:
+ uint32_t width_;
+ uint32_t height_;
+
+ Member<DOMUint16Array> data_;
+ gfx::Transform norm_texture_from_norm_view_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_DEPTH_INFORMATION_H_
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl
new file mode 100644
index 00000000000..0479dcc607a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_depth_information.idl
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ SecureContext,
+ Exposed=Window,
+ RuntimeEnabled=WebXRDepth
+] interface XRDepthInformation {
+ [SameObject, MeasureAs=XRDepthInformationDataAttribute]
+ readonly attribute Uint16Array data;
+
+ readonly attribute unsigned long width;
+ readonly attribute unsigned long height;
+
+ [SameObject] readonly attribute XRRigidTransform normTextureFromNormView;
+
+ [RaisesException, MeasureAs=XRDepthInformationGetDepth]
+ float getDepth(unsigned long column, unsigned long row);
+};
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 5b1de602b69..41c90af41d9 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.cc
@@ -24,6 +24,9 @@ namespace {
const char kInactiveFrame[] =
"XRFrame access outside the callback that produced it is invalid.";
+const char kInvalidView[] =
+ "XRView passed in to the method did not originate from current XRFrame.";
+
const char kNonAnimationFrame[] =
"getViewerPose can only be called on XRFrame objects passed to "
"XRSession.requestAnimationFrame callbacks.";
@@ -128,6 +131,26 @@ XRLightEstimate* XRFrame::getLightEstimate(
return light_probe->getLightEstimate();
}
+XRDepthInformation* XRFrame::getDepthInformation(
+ XRView* view,
+ ExceptionState& exception_state) const {
+ DVLOG(2) << __func__;
+
+ if (!is_active_) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInactiveFrame);
+ return nullptr;
+ }
+
+ if (this != view->frame()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidView);
+ return nullptr;
+ }
+
+ return session_->GetDepthInformation();
+}
+
// Return an XRPose that has a transform of basespace_from_space, while
// accounting for the base pose matrix of this frame. If computing a transform
// isn't possible, return nullptr.
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 b19ca82aa16..1865317b377 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.h
@@ -19,6 +19,7 @@ namespace blink {
class ExceptionState;
class XRAnchorSet;
+class XRDepthInformation;
class XRHitTestResult;
class XRHitTestSource;
class XRInputSource;
@@ -31,6 +32,7 @@ class XRSession;
class XRSpace;
class XRTransientInputHitTestResult;
class XRTransientInputHitTestSource;
+class XRView;
class XRViewerPose;
class XRWorldInformation;
@@ -47,6 +49,9 @@ class XRFrame final : public ScriptWrappable {
XRWorldInformation* worldInformation() const { return world_information_; }
XRAnchorSet* trackedAnchors() const;
XRLightEstimate* getLightEstimate(XRLightProbe*, ExceptionState&) const;
+ XRDepthInformation* getDepthInformation(
+ XRView* view,
+ ExceptionState& exception_state) const;
void Trace(Visitor*) const override;
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 17bc688c46a..0149aa50314 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame.idl
@@ -29,4 +29,7 @@
[RuntimeEnabled=WebXRLightEstimation, RaisesException]
XRLightEstimate? getLightEstimate(XRLightProbe lightProbe);
+
+ [RuntimeEnabled=WebXRDepth, RaisesException, MeasureAs=XRFrameGetDepthInformation]
+ XRDepthInformation getDepthInformation(XRView view);
};
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 beb42324b8f..7e69b3a85fe 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
@@ -60,6 +60,11 @@ XRFrameProvider::XRFrameProvider(XRSystem* xr)
immersive_presentation_provider_(xr->GetExecutionContext()),
last_has_focus_(xr->IsFrameFocused()) {}
+void XRFrameProvider::AddImmersiveSessionObserver(
+ ImmersiveSessionObserver* observer) {
+ immersive_observers_.insert(observer);
+}
+
void XRFrameProvider::OnSessionStarted(
XRSession* session,
device::mojom::blink::XRSessionPtr session_ptr) {
@@ -73,6 +78,10 @@ void XRFrameProvider::OnSessionStarted(
immersive_session_ = session;
+ for (auto& observer : immersive_observers_) {
+ observer->OnImmersiveSessionStart();
+ }
+
immersive_data_provider_.Bind(
std::move(session_ptr->data_provider),
xr_->GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
@@ -156,6 +165,10 @@ void XRFrameProvider::OnSessionEnded(XRSession* session) {
session->GetExecutionContext(),
session->GetExecutionContext()->GetTaskRunner(
TaskType::kMiscPlatformAPI));
+
+ for (auto& observer : immersive_observers_) {
+ observer->OnImmersiveSessionEnd();
+ }
} else {
non_immersive_data_providers_.erase(session);
requesting_sessions_.erase(session);
@@ -309,6 +322,10 @@ void XRFrameProvider::OnImmersiveFrameData(
pending_immersive_vsync_ = false;
+ for (auto& observer : immersive_observers_) {
+ observer->OnImmersiveFrame();
+ }
+
// Post a task to handle scheduled animations after the current
// execution context finishes, so that we yield to non-mojo tasks in
// between frames. Executing mojo tasks back to back within the same
@@ -689,6 +706,7 @@ void XRFrameProvider::Trace(Visitor* visitor) const {
visitor->Trace(immersive_presentation_provider_);
visitor->Trace(non_immersive_data_providers_);
visitor->Trace(requesting_sessions_);
+ visitor->Trace(immersive_observers_);
}
} // namespace blink
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 b36b635acd8..b827363a137 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
@@ -26,6 +26,14 @@ class XRWebGLLayer;
// pose information for a given XRDevice.
class XRFrameProvider final : public GarbageCollected<XRFrameProvider> {
public:
+ // Class
+ class ImmersiveSessionObserver : public GarbageCollectedMixin {
+ public:
+ virtual void OnImmersiveSessionStart() = 0;
+ virtual void OnImmersiveSessionEnd() = 0;
+ virtual void OnImmersiveFrame() = 0;
+ };
+
explicit XRFrameProvider(XRSystem*);
XRSession* immersive_session() const { return immersive_session_; }
@@ -54,6 +62,10 @@ class XRFrameProvider final : public GarbageCollected<XRFrameProvider> {
return immersive_data_provider_.get();
}
+ // Adds an ImmersiveSessionObserver. Observers will be automatically removed
+ // by Oilpan when they are destroyed, and their WeakMember becomes null.
+ void AddImmersiveSessionObserver(ImmersiveSessionObserver*);
+
virtual void Trace(Visitor*) const;
private:
@@ -105,6 +117,10 @@ class XRFrameProvider final : public GarbageCollected<XRFrameProvider> {
device::mojom::blink::VRPosePtr immersive_frame_pose_;
bool is_immersive_frame_position_emulated_ = false;
+ // Note: Oilpan automatically removes destroyed observers from
+ // |immersive_observers_| and does not need an explicit removal.
+ HeapHashSet<WeakMember<ImmersiveSessionObserver>> immersive_observers_;
+
// Time the first immersive frame has arrived - used to align the monotonic
// clock the devices use with the base::TimeTicks.
base::Optional<base::TimeTicks> first_immersive_frame_time_;
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h
index b4d5e90448e..4340096f7eb 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_input_source.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
#include "base/optional.h"
-#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
#include "third_party/blink/renderer/modules/xr/xr_native_origin_information.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_plane.h b/chromium/third_party/blink/renderer/modules/xr/xr_plane.h
index a58b210f052..7311e3ca343 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_plane.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_plane.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/optional.h"
+#include "device/vr/public/mojom/pose.h"
#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h"
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 b35a970eefc..d77ee112518 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -12,6 +12,7 @@
#include "base/auto_reset.h"
#include "base/metrics/histogram_macros.h"
+#include "base/numerics/ranges.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/bindings/modules/v8/v8_xr_frame_request_callback.h"
@@ -30,6 +31,7 @@
#include "third_party/blink/renderer/modules/xr/xr_anchor_set.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_depth_information.h"
#include "third_party/blink/renderer/modules/xr/xr_dom_overlay_state.h"
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
@@ -99,24 +101,27 @@ const char kEntityTypesNotSpecified[] =
const double kDegToRad = M_PI / 180.0;
+const float kMinDefaultFramebufferScale = 0.1f;
+const float kMaxDefaultFramebufferScale = 1.0f;
+
// Indices into the views array.
const unsigned int kMonoOrStereoLeftView = 0;
const unsigned int kStereoRightView = 1;
void UpdateViewFromEyeParameters(
- XRViewData& view,
+ XRViewData* view,
const device::mojom::blink::VREyeParametersPtr& eye,
double depth_near,
double depth_far) {
const device::mojom::blink::VRFieldOfViewPtr& fov = eye->field_of_view;
- view.UpdateProjectionMatrixFromFoV(
+ view->UpdateProjectionMatrixFromFoV(
fov->up_degrees * kDegToRad, fov->down_degrees * kDegToRad,
fov->left_degrees * kDegToRad, fov->right_degrees * kDegToRad, depth_near,
depth_far);
const TransformationMatrix matrix(eye->head_from_eye.matrix());
- view.SetHeadFromEyeTransform(matrix);
+ view->SetHeadFromEyeTransform(matrix);
}
// Returns the session feature corresponding to the given reference space type.
@@ -292,6 +297,7 @@ void XRSession::MetricsReporter::ReportFeatureUsed(
case XRSessionFeature::ANCHORS:
case XRSessionFeature::CAMERA_ACCESS:
case XRSessionFeature::PLANE_DETECTION:
+ case XRSessionFeature::DEPTH:
// Not recording metrics for these features currently.
break;
}
@@ -305,6 +311,7 @@ XRSession::XRSession(
EnvironmentBlendMode environment_blend_mode,
InteractionMode interaction_mode,
bool uses_input_eventing,
+ float default_framebuffer_scale,
bool sensorless_session,
XRSessionFeatureSet enabled_features)
: xr_(xr),
@@ -328,6 +335,11 @@ XRSession::XRSession(
// Ensure that frame focus is considered in the initial visibilityState.
UpdateVisibilityState();
+ // Clamp to a reasonable min/max size for the default framebuffer scale.
+ default_framebuffer_scale_ =
+ base::ClampToRange(default_framebuffer_scale, kMinDefaultFramebufferScale,
+ kMaxDefaultFramebufferScale);
+
world_tracking_state_ = MakeGarbageCollected<XRWorldTrackingState>(
IsFeatureEnabled(device::mojom::XRSessionFeature::PLANE_DETECTION));
@@ -683,6 +695,19 @@ XRSession::GetStationaryReferenceSpace() const {
return result;
}
+void XRSession::ScheduleVideoFrameCallbacksExecution(
+ ExecuteVfcCallback execute_vfc_callback) {
+ vfc_execution_queue_.push_back(std::move(execute_vfc_callback));
+ MaybeRequestFrame();
+}
+
+void XRSession::ExecuteVideoFrameCallbacks(double timestamp) {
+ Vector<ExecuteVfcCallback> execute_vfc_callbacks;
+ vfc_execution_queue_.swap(execute_vfc_callbacks);
+ for (auto& callback : execute_vfc_callbacks)
+ std::move(callback).Run(timestamp);
+}
+
int XRSession::requestAnimationFrame(V8XRFrameRequestCallback* callback) {
DVLOG(3) << __func__;
@@ -1135,6 +1160,41 @@ void XRSession::ProcessHitTestData(
}
}
+void XRSession::ProcessDepthData(
+ device::mojom::blink::XRDepthDataPtr depth_data) {
+ DVLOG(3) << __func__ << ": depth_data valid? " << !!depth_data;
+
+ if (depth_data) {
+ switch (depth_data->which()) {
+ case device::mojom::blink::XRDepthData::Tag::DATA_STILL_VALID:
+ // Stale depth buffer is still the most recent information we have.
+ // Current API shape is not well-suited to return data pertaining to
+ // older frames, so just discard what we have.
+ depth_data_ = nullptr;
+ break;
+ case device::mojom::blink::XRDepthData::Tag::UPDATED_DEPTH_DATA:
+ // Just store the current depth data as a member - we will need to
+ // construct instances of XRDepthInformation once the app requests them
+ // anyway.
+ depth_data_ = std::move(depth_data->get_updated_depth_data());
+ break;
+ }
+ } else {
+ // Device did not return new pixel data.
+ depth_data_ = nullptr;
+ }
+}
+
+XRDepthInformation* XRSession::GetDepthInformation() const {
+ DVLOG(2) << __func__;
+
+ if (!depth_data_) {
+ return nullptr;
+ }
+
+ return MakeGarbageCollected<XRDepthInformation>(*depth_data_);
+}
+
ScriptPromise XRSession::requestLightProbe(ScriptState* script_state,
ExceptionState& exception_state) {
if (ended_) {
@@ -1277,12 +1337,11 @@ void XRSession::HandleShutdown() {
double XRSession::NativeFramebufferScale() const {
if (immersive()) {
- double scale = display_info_->webxr_default_framebuffer_scale;
- DCHECK(scale);
+ DCHECK(default_framebuffer_scale_);
// Return the inverse of the default scale, since that's what we'll need to
// multiply the default size by to get back to the native size.
- return 1.0 / scale;
+ return 1.0 / default_framebuffer_scale_;
}
return 1.0;
}
@@ -1292,7 +1351,7 @@ DoubleSize XRSession::DefaultFramebufferSize() const {
return OutputCanvasSize();
}
- double scale = display_info_->webxr_default_framebuffer_scale;
+ double scale = default_framebuffer_scale_;
double width = display_info_->left_eye->render_width;
double height = display_info_->left_eye->render_height;
@@ -1382,7 +1441,8 @@ void XRSession::MaybeRequestFrame() {
// If we have an outstanding callback registered, then we know that the page
// actually wants frames.
- bool page_wants_frame = !callback_collection_->IsEmpty();
+ bool page_wants_frame =
+ !callback_collection_->IsEmpty() || !vfc_execution_queue_.IsEmpty();
// A page can process frames if it has its appropriate base layer set and has
// indicated that it actually wants frames.
@@ -1531,6 +1591,7 @@ void XRSession::UpdateWorldUnderstandingStateForFrame(
frame_data->detected_planes_data.get(), timestamp);
ProcessAnchorsData(frame_data->anchors_data.get(), timestamp);
ProcessHitTestData(frame_data->hit_test_subscription_results.get());
+ ProcessDepthData(std::move(frame_data->depth_data));
const device::mojom::blink::XRLightEstimationData* light_data =
frame_data->light_estimation_data.get();
@@ -1541,6 +1602,7 @@ void XRSession::UpdateWorldUnderstandingStateForFrame(
world_information_->ProcessPlaneInformation(nullptr, timestamp);
ProcessAnchorsData(nullptr, timestamp);
ProcessHitTestData(nullptr);
+ ProcessDepthData(nullptr);
if (world_light_probe_) {
world_light_probe_->ProcessLightEstimationData(nullptr, timestamp);
@@ -1633,6 +1695,7 @@ void XRSession::OnFrame(
// happen within these calls. resolving_frame_ will be true for the duration
// of the callbacks.
base::AutoReset<bool> resolving(&resolving_frame_, true);
+ ExecuteVideoFrameCallbacks(timestamp);
callback_collection_->ExecuteCallbacks(this, timestamp, presentation_frame);
// The session might have ended in the middle of the frame. Only call
@@ -2008,7 +2071,7 @@ void XRSession::SetXRDisplayInfo(
display_info_ = std::move(display_info);
}
-Vector<XRViewData>& XRSession::views() {
+const HeapVector<Member<XRViewData>>& XRSession::views() {
// TODO(bajones): For now we assume that immersive sessions render a stereo
// pair of views and non-immersive sessions render a single view. That doesn't
// always hold true, however, so the view configuration should ultimately come
@@ -2017,9 +2080,10 @@ Vector<XRViewData>& XRSession::views() {
if (immersive()) {
// If we don't already have the views allocated, do so now.
if (views_.IsEmpty()) {
- views_.emplace_back(XRView::kEyeLeft);
+ views_.emplace_back(MakeGarbageCollected<XRViewData>(XRView::kEyeLeft));
if (display_info_->right_eye) {
- views_.emplace_back(XRView::kEyeRight);
+ views_.emplace_back(
+ MakeGarbageCollected<XRViewData>(XRView::kEyeRight));
}
}
// In immersive mode the projection and view matrices must be aligned with
@@ -2034,7 +2098,7 @@ Vector<XRViewData>& XRSession::views() {
}
} else {
if (views_.IsEmpty()) {
- views_.emplace_back(XRView::kEyeNone);
+ views_.emplace_back(MakeGarbageCollected<XRViewData>(XRView::kEyeNone));
}
float aspect = 1.0f;
@@ -2051,7 +2115,7 @@ Vector<XRViewData>& XRSession::views() {
// inlineVerticalFieldOfView should only be null in immersive mode.
DCHECK(inline_vertical_fov.has_value());
- views_[kMonoOrStereoLeftView].UpdateProjectionMatrixFromAspect(
+ views_[kMonoOrStereoLeftView]->UpdateProjectionMatrixFromAspect(
inline_vertical_fov.value(), aspect, render_state_->depthNear(),
render_state_->depthFar());
}
@@ -2063,7 +2127,9 @@ Vector<XRViewData>& XRSession::views() {
}
bool XRSession::HasPendingActivity() const {
- return !callback_collection_->IsEmpty() && !ended_;
+ return (!callback_collection_->IsEmpty() ||
+ !vfc_execution_queue_.IsEmpty()) &&
+ !ended_;
}
void XRSession::Trace(Visitor* visitor) const {
@@ -2090,6 +2156,7 @@ void XRSession::Trace(Visitor* visitor) const {
visitor->Trace(prev_base_layer_);
visitor->Trace(hit_test_source_ids_to_hit_test_sources_);
visitor->Trace(hit_test_source_ids_to_transient_input_hit_test_sources_);
+ visitor->Trace(views_);
EventTargetWithInlineData::Trace(visitor);
}
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 d59f2f0ab08..e36da85e9db 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.h
@@ -41,6 +41,7 @@ class V8XRFrameRequestCallback;
class XRAnchor;
class XRAnchorSet;
class XRCanvasInputProvider;
+class XRDepthInformation;
class XRDOMOverlayState;
class XRHitTestOptionsInit;
class XRHitTestSource;
@@ -77,6 +78,14 @@ class XRSession final
static constexpr char kAnchorsFeatureNotSupported[] =
"Anchors feature is not supported by the session.";
+ // Runs all the video.requestVideoFrameCallback() callbacks associated with
+ // one HTMLVideoElement. |double| is the |high_res_now_ms|, derived from
+ // MonotonicTimeToZeroBasedDocumentTime(|current_frame_time|), to be passed as
+ // the "now" parameter when executing rVFC callbacks. In other words, a
+ // video.rVFC and an xrSession.rAF callback share the same "now" parameters if
+ // they are run in the same turn of the render loop.
+ using ExecuteVfcCallback = base::OnceCallback<void(double)>;
+
enum EnvironmentBlendMode {
kBlendModeOpaque = 0,
kBlendModeAdditive,
@@ -108,6 +117,7 @@ class XRSession final
EnvironmentBlendMode environment_blend_mode,
InteractionMode interaction_mode,
bool uses_input_eventing,
+ float default_framebuffer_scale,
bool sensorless_session,
XRSessionFeatureSet enabled_features);
~XRSession() override = default;
@@ -242,7 +252,7 @@ class XRSession final
void OnButtonEvent(
device::mojom::blink::XRInputSourceStatePtr input_source) override;
- Vector<XRViewData>& views();
+ const HeapVector<Member<XRViewData>>& views();
void AddTransientInputSource(XRInputSource* input_source);
void RemoveTransientInputSource(XRInputSource* input_source);
@@ -318,6 +328,8 @@ class XRSession final
base::Optional<TransformationMatrix> GetMojoFrom(
device::mojom::blink::XRReferenceSpaceType space_type) const;
+ XRDepthInformation* GetDepthInformation() const;
+
// Creates presentation frame based on current state of the session.
// State currently used in XRFrame creation is mojo_from_viewer_ and
// world_information_. The created XRFrame also stores a reference to this
@@ -345,6 +357,10 @@ class XRSession final
// Sets the metrics reporter for this session. This should only be done once.
void SetMetricsReporter(std::unique_ptr<MetricsReporter> reporter);
+ // Queues up the execution of video.requestVideoFrameCallback() callbacks for
+ // a specific HTMLVideoELement, for the next requestAnimationFrame() call.
+ void ScheduleVideoFrameCallbacksExecution(ExecuteVfcCallback);
+
private:
class XRSessionResizeObserverDelegate;
@@ -410,8 +426,12 @@ class XRSession final
const device::mojom::blink::XRHitTestSubscriptionResultsData*
hit_test_data);
+ void ProcessDepthData(device::mojom::blink::XRDepthDataPtr depth_data);
+
void HandleShutdown();
+ void ExecuteVideoFrameCallbacks(double timestamp);
+
const Member<XRSystem> xr_;
const device::mojom::blink::XRSessionMode mode_;
const bool environment_integration_;
@@ -497,7 +517,7 @@ class XRSession final
HashSet<uint64_t> hit_test_source_ids_;
HashSet<uint64_t> hit_test_source_for_transient_input_ids_;
- Vector<XRViewData> views_;
+ HeapVector<Member<XRViewData>> views_;
Member<XRInputSourceArray> input_sources_;
Member<XRWebGLLayer> prev_base_layer_;
@@ -524,10 +544,16 @@ class XRSession final
HeapMojoWrapperMode::kWithoutContextObserver>
input_receiver_;
+ // Used to schedule video.rVFC callbacks for immersive sessions.
+ Vector<ExecuteVfcCallback> vfc_execution_queue_;
+
Member<XRFrameRequestCallbackCollection> callback_collection_;
// Viewer pose in mojo space.
std::unique_ptr<TransformationMatrix> mojo_from_viewer_;
+ // Current depth data buffer.
+ device::mojom::blink::XRDepthDataUpdatedPtr depth_data_;
+
bool pending_frame_ = false;
bool resolving_frame_ = false;
bool update_views_next_frame_ = false;
@@ -544,6 +570,7 @@ class XRSession final
int output_height_ = 1;
bool uses_input_eventing_ = false;
+ float default_framebuffer_scale_ = 1.0;
// Indicates that this is a sensorless session which should only support the
// identity reference space.
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_system.cc b/chromium/third_party/blink/renderer/modules/xr/xr_system.cc
index 17d7dfb25c1..7914f42774b 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_system.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -137,6 +137,9 @@ base::Optional<device::mojom::XRSessionFeature> StringToXRSessionFeature(
} else if (RuntimeEnabledFeatures::WebXRPlaneDetectionEnabled(context) &&
feature_string == "plane-detection") {
return device::mojom::XRSessionFeature::PLANE_DETECTION;
+ } else if (RuntimeEnabledFeatures::WebXRDepthEnabled(context) &&
+ feature_string == "depth-sensing") {
+ return device::mojom::XRSessionFeature::DEPTH;
}
return base::nullopt;
@@ -172,8 +175,9 @@ bool IsFeatureValidForMode(device::mojom::XRSessionFeature feature,
case device::mojom::XRSessionFeature::LIGHT_ESTIMATION:
case device::mojom::XRSessionFeature::CAMERA_ACCESS:
case device::mojom::XRSessionFeature::PLANE_DETECTION:
- // Fallthrough - light estimation, camera access and plane detection APIs
- // are all valid only for immersive AR mode for now.
+ case device::mojom::XRSessionFeature::DEPTH:
+ // Fallthrough - light estimation, camera access, plane detection and
+ // depth APIs are all valid only for immersive AR mode for now.
return mode == device::mojom::blink::XRSessionMode::kImmersiveAr;
}
}
@@ -196,6 +200,7 @@ bool HasRequiredFeaturePolicy(const ExecutionContext* context,
case device::mojom::XRSessionFeature::ANCHORS:
case device::mojom::XRSessionFeature::CAMERA_ACCESS:
case device::mojom::XRSessionFeature::PLANE_DETECTION:
+ case device::mojom::XRSessionFeature::DEPTH:
return context->IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature::kWebXr,
ReportOptions::kReportOnFailure);
@@ -249,6 +254,18 @@ const char* GetConsoleMessage(device::mojom::RequestSessionError error) {
}
}
+bool IsFeatureRequested(
+ device::mojom::XRSessionFeatureRequestStatus requestStatus) {
+ switch (requestStatus) {
+ case device::mojom::XRSessionFeatureRequestStatus::kOptionalAccepted:
+ case device::mojom::XRSessionFeatureRequestStatus::kRequired:
+ return true;
+ case device::mojom::XRSessionFeatureRequestStatus::kNotRequested:
+ case device::mojom::XRSessionFeatureRequestStatus::kOptionalRejected:
+ return false;
+ }
+}
+
} // namespace
// Ensure that the inline session request is allowed, if not
@@ -479,6 +496,8 @@ void XRSystem::PendingRequestSessionQuery::ReportRequestSessionResult(
GetFeatureRequestStatus(XRSessionFeature::REF_SPACE_UNBOUNDED, session);
auto feature_request_dom_overlay =
GetFeatureRequestStatus(XRSessionFeature::DOM_OVERLAY, session);
+ auto feature_request_depth_sensing =
+ GetFeatureRequestStatus(XRSessionFeature::DEPTH, session);
ukm::builders::XR_WebXR_SessionRequest(ukm_source_id_)
.SetMode(static_cast<int64_t>(mode_))
@@ -494,12 +513,22 @@ void XRSystem::PendingRequestSessionQuery::ReportRequestSessionResult(
// If the session was successfully created and DOM overlay was requested,
// count this as a use of the DOM overlay feature.
if (session && status == SessionRequestStatus::kSuccess &&
- feature_request_dom_overlay !=
- device::mojom::XRSessionFeatureRequestStatus::kNotRequested) {
+ IsFeatureRequested(feature_request_dom_overlay)) {
+ DVLOG(2) << __func__ << ": DOM overlay was requested, logging a UseCounter";
UseCounter::Count(session->GetExecutionContext(),
WebFeature::kXRDOMOverlay);
}
+ // If the session was successfully created and depth-sensing was requested,
+ // count this as a use of depth sensing feature.
+ if (session && status == SessionRequestStatus::kSuccess &&
+ IsFeatureRequested(feature_request_depth_sensing)) {
+ DVLOG(2) << __func__
+ << ": depth sensing was requested, logging a UseCounter";
+ UseCounter::Count(session->GetExecutionContext(),
+ WebFeature::kXRDepthSensing);
+ }
+
if (session && metrics_recorder) {
mojo::Remote<device::mojom::blink::XRSessionMetricsRecorder> recorder(
std::move(metrics_recorder));
@@ -1259,17 +1288,31 @@ ScriptPromise XRSystem::requestSession(ScriptState* script_state,
void XRSystem::MakeXrCompatibleAsync(
device::mojom::blink::VRService::MakeXrCompatibleCallback callback) {
+ if (!GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kWebXr)) {
+ std::move(callback).Run(
+ device::mojom::XrCompatibleResult::kWebXrFeaturePolicyBlocked);
+ return;
+ }
+
TryEnsureService();
if (service_.is_bound()) {
service_->MakeXrCompatible(std::move(callback));
} else {
- std::move(callback).Run(device::mojom::XrCompatibleResult::kNotCompatible);
+ std::move(callback).Run(
+ device::mojom::XrCompatibleResult::kNoDeviceAvailable);
}
}
void XRSystem::MakeXrCompatibleSync(
device::mojom::XrCompatibleResult* xr_compatible_result) {
- *xr_compatible_result = device::mojom::XrCompatibleResult::kNotCompatible;
+ if (!GetExecutionContext()->IsFeatureEnabled(
+ mojom::blink::FeaturePolicyFeature::kWebXr)) {
+ *xr_compatible_result =
+ device::mojom::XrCompatibleResult::kWebXrFeaturePolicyBlocked;
+ return;
+ }
+ *xr_compatible_result = device::mojom::XrCompatibleResult::kNoDeviceAvailable;
TryEnsureService();
if (service_.is_bound())
@@ -1381,11 +1424,11 @@ void XRSystem::OnRequestSessionReturned(
enabled_features.insert(feature);
}
- XRSession* session =
- CreateSession(query->mode(), blend_mode, interaction_mode,
- std::move(session_ptr->client_receiver),
- std::move(session_ptr->display_info),
- session_ptr->uses_input_eventing, enabled_features);
+ XRSession* session = CreateSession(
+ query->mode(), blend_mode, interaction_mode,
+ std::move(session_ptr->client_receiver),
+ std::move(session_ptr->display_info), session_ptr->uses_input_eventing,
+ session_ptr->default_framebuffer_scale, enabled_features);
frameProvider()->OnSessionStarted(session, std::move(session_ptr));
@@ -1490,11 +1533,13 @@ XRSession* XRSystem::CreateSession(
client_receiver,
device::mojom::blink::VRDisplayInfoPtr display_info,
bool uses_input_eventing,
+ float default_framebuffer_scale,
XRSessionFeatureSet enabled_features,
bool sensorless_session) {
XRSession* session = MakeGarbageCollected<XRSession>(
this, std::move(client_receiver), mode, blend_mode, interaction_mode,
- uses_input_eventing, sensorless_session, std::move(enabled_features));
+ uses_input_eventing, default_framebuffer_scale, sensorless_session,
+ std::move(enabled_features));
if (display_info)
session->SetXRDisplayInfo(std::move(display_info));
sessions_.insert(session);
@@ -1510,6 +1555,7 @@ XRSession* XRSystem::CreateSensorlessInlineSession() {
device::mojom::blink::XRSessionMode::kInline, blend_mode,
interaction_mode, mojo::NullReceiver() /* client receiver */,
nullptr /* display_info */, false /* uses_input_eventing */,
+ 1.0 /* default_framebuffer_scale */,
{device::mojom::XRSessionFeature::REF_SPACE_VIEWER},
true /* sensorless_session */);
}
diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_system.h b/chromium/third_party/blink/renderer/modules/xr/xr_system.h
index 126e490181b..ed199681cba 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_system.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_system.h
@@ -396,6 +396,7 @@ class XRSystem final : public EventTargetWithInlineData,
client_receiver,
device::mojom::blink::VRDisplayInfoPtr display_info,
bool uses_input_eventing,
+ float default_framebuffer_scale,
XRSessionFeatureSet enabled_features,
bool sensorless_session = false);
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 d6e889e7ffb..242ffa4af8a 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.cc
@@ -10,8 +10,8 @@
namespace blink {
-XRView::XRView(XRFrame* frame, const XRViewData& view_data)
- : eye_(view_data.Eye()), frame_(frame) {
+XRView::XRView(XRFrame* frame, XRViewData* view_data)
+ : eye_(view_data->Eye()), frame_(frame), view_data_(view_data) {
switch (eye_) {
case kEyeLeft:
eye_string_ = "left";
@@ -23,9 +23,9 @@ XRView::XRView(XRFrame* frame, const XRViewData& view_data)
eye_string_ = "none";
}
ref_space_from_eye_ =
- MakeGarbageCollected<XRRigidTransform>(view_data.Transform());
+ MakeGarbageCollected<XRRigidTransform>(view_data->Transform());
projection_matrix_ =
- transformationMatrixToDOMFloat32Array(view_data.ProjectionMatrix());
+ transformationMatrixToDOMFloat32Array(view_data->ProjectionMatrix());
}
XRFrame* XRView::frame() const {
@@ -148,6 +148,7 @@ void XRView::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(projection_matrix_);
visitor->Trace(ref_space_from_eye_);
+ visitor->Trace(view_data_);
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 37596e43428..6d8570eec26 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_view.h
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_view.h
@@ -25,12 +25,13 @@ class MODULES_EXPORT XRView final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- XRView(XRFrame*, const XRViewData&);
+ XRView(XRFrame*, XRViewData*);
enum XREye { kEyeNone = 0, kEyeLeft = 1, kEyeRight = 2 };
const String& eye() const { return eye_string_; }
XREye EyeValue() const { return eye_; }
+ XRViewData* ViewData() const { return view_data_; }
XRFrame* frame() const;
XRSession* session() const;
@@ -50,11 +51,12 @@ class MODULES_EXPORT XRView final : public ScriptWrappable {
XREye eye_;
String eye_string_;
Member<XRFrame> frame_;
+ Member<XRViewData> view_data_;
Member<XRRigidTransform> ref_space_from_eye_;
Member<DOMFloat32Array> projection_matrix_;
};
-class MODULES_EXPORT XRViewData {
+class MODULES_EXPORT XRViewData final : public GarbageCollected<XRViewData> {
public:
XRViewData(XRView::XREye eye) : eye_(eye) {}
@@ -83,6 +85,8 @@ class MODULES_EXPORT XRViewData {
return projection_matrix_;
}
+ void Trace(Visitor*) const {}
+
private:
const XRView::XREye eye_;
TransformationMatrix ref_space_from_eye_;
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
index 6d9170f7ade..2c4a94f358f 100644
--- a/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc
+++ b/chromium/third_party/blink/renderer/modules/xr/xr_viewer_pose.cc
@@ -16,14 +16,14 @@ XRViewerPose::XRViewerPose(XRFrame* frame,
: XRPose(pose_model_matrix, frame->session()->EmulatedPosition()) {
DVLOG(3) << __func__ << ": emulatedPosition()=" << emulatedPosition();
- Vector<XRViewData>& view_data = frame->session()->views();
+ const HeapVector<Member<XRViewData>>& view_data = frame->session()->views();
bool camera_access_enabled = frame->session()->IsFeatureEnabled(
device::mojom::XRSessionFeature::CAMERA_ACCESS);
// Snapshot the session's current views.
- for (XRViewData& view : view_data) {
- view.UpdatePoseMatrix(transform_->TransformMatrix());
+ for (XRViewData* view : view_data) {
+ view->UpdatePoseMatrix(transform_->TransformMatrix());
XRView* xr_view = MakeGarbageCollected<XRView>(frame, view);
views_.push_back(xr_view);
if (camera_access_enabled) {